@agimon-ai/po-user-feedback 0.0.0-alpha.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.
@@ -0,0 +1,627 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ let _agimon_ai_po_core_serverFacet = require("@agimon-ai/po-core/serverFacet");
6
+ let _agimon_ai_po_core_extensionFile = require("@agimon-ai/po-core/extensionFile");
7
+ let _agimon_ai_po_core_help = require("@agimon-ai/po-core/help");
8
+ let _agimon_ai_po_core_voiceTools = require("@agimon-ai/po-core/voiceTools");
9
+ let typebox = require("typebox");
10
+ //#region src/services/questionnaireCoordinator/index.ts
11
+ function cancelledResult(entry) {
12
+ return {
13
+ answers: entry.latestAnswers.map((answer) => ({ ...answer })),
14
+ cancelled: true
15
+ };
16
+ }
17
+ var QuestionnaireCoordinator = class {
18
+ pending = [];
19
+ running = /* @__PURE__ */ new Set();
20
+ active;
21
+ nextRequestId = 1;
22
+ accepting = true;
23
+ enqueue(runner, externalSignal) {
24
+ if (!this.accepting || externalSignal?.aborted) return Promise.resolve({
25
+ answers: [],
26
+ cancelled: true
27
+ });
28
+ return new Promise((resolve, reject) => {
29
+ const entry = {
30
+ id: this.nextRequestId,
31
+ runner,
32
+ controller: new AbortController(),
33
+ ...externalSignal ? { externalSignal } : {},
34
+ latestAnswers: [],
35
+ state: "queued",
36
+ resolve,
37
+ reject
38
+ };
39
+ this.nextRequestId += 1;
40
+ const abort = () => this.cancel(entry);
41
+ externalSignal?.addEventListener("abort", abort, { once: true });
42
+ entry.removeAbortListener = () => externalSignal?.removeEventListener("abort", abort);
43
+ this.pending.push(entry);
44
+ this.startNext();
45
+ });
46
+ }
47
+ shutdown() {
48
+ if (!this.accepting && !this.active && this.pending.length === 0) return;
49
+ this.accepting = false;
50
+ if (this.active) this.cancel(this.active);
51
+ while (this.pending.length > 0) {
52
+ const entry = this.pending[0];
53
+ if (!entry) break;
54
+ this.cancel(entry);
55
+ }
56
+ }
57
+ /** Waits for every started presenter to observe cancellation and finish. */
58
+ async waitForIdle() {
59
+ while (this.running.size > 0) await Promise.allSettled(this.running);
60
+ }
61
+ startNext() {
62
+ if (!this.accepting || this.active) return;
63
+ const entry = this.pending.shift();
64
+ if (!entry) return;
65
+ entry.state = "active";
66
+ this.active = entry;
67
+ const reportProgress = (result) => {
68
+ if (this.active?.id !== entry.id || entry.state !== "active") return;
69
+ entry.latestAnswers = result.answers.map((answer) => ({ ...answer }));
70
+ };
71
+ let operation;
72
+ try {
73
+ operation = entry.runner({
74
+ signal: entry.controller.signal,
75
+ reportProgress
76
+ });
77
+ } catch (error) {
78
+ operation = Promise.reject(error);
79
+ }
80
+ this.running.add(operation);
81
+ operation.then((result) => this.complete(entry, result), (error) => this.fail(entry, error)).finally(() => this.running.delete(operation));
82
+ }
83
+ complete(entry, result) {
84
+ if (this.active?.id !== entry.id || entry.state !== "active") return;
85
+ this.releaseActive(entry);
86
+ entry.resolve(result);
87
+ this.startNext();
88
+ }
89
+ fail(entry, error) {
90
+ if (this.active?.id !== entry.id || entry.state !== "active") return;
91
+ this.releaseActive(entry);
92
+ entry.reject(error);
93
+ this.startNext();
94
+ }
95
+ cancel(entry) {
96
+ if (entry.state === "settled") return;
97
+ if (entry.state === "queued") {
98
+ const index = this.pending.indexOf(entry);
99
+ this.pending.splice(index, 1);
100
+ entry.state = "settled";
101
+ entry.removeAbortListener?.();
102
+ entry.controller.abort();
103
+ entry.resolve(cancelledResult(entry));
104
+ return;
105
+ }
106
+ const result = cancelledResult(entry);
107
+ this.releaseActive(entry);
108
+ entry.controller.abort();
109
+ entry.resolve(result);
110
+ this.startNext();
111
+ }
112
+ releaseActive(entry) {
113
+ entry.state = "settled";
114
+ entry.removeAbortListener?.();
115
+ this.active = void 0;
116
+ }
117
+ };
118
+ //#endregion
119
+ //#region src/extensions/workspaces/sessions/(backend)/_lib/root.server.ts
120
+ const root = (0, _agimon_ai_po_core_extensionFile.defineRoot)((_context) => {
121
+ const coordinator = new QuestionnaireCoordinator();
122
+ return {
123
+ value: { coordinator },
124
+ onDispose: async () => {
125
+ coordinator.shutdown();
126
+ await coordinator.waitForIdle();
127
+ }
128
+ };
129
+ });
130
+ //#endregion
131
+ //#region src/extensions/workspaces/sessions/(backend)/root.server.ts
132
+ var root_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoot)(root);
133
+ //#endregion
134
+ //#region src/extensions/workspaces/sessions/(backend)/resource/poUseUserFeedback.server.ts
135
+ var poUseUserFeedback_server_default = (0, _agimon_ai_po_core_extensionFile.defineResource)({
136
+ name: "po-use-user-feedback",
137
+ when: _agimon_ai_po_core_help.DOOM_HELP_WHEN,
138
+ kind: "skill",
139
+ read: () => (0, _agimon_ai_po_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-user-feedback/SKILL.md")
140
+ });
141
+ //#endregion
142
+ //#region src/constants/questionnaire.ts
143
+ const RESERVED_LABELS = [
144
+ "Other",
145
+ "Type something.",
146
+ "Next"
147
+ ];
148
+ //#endregion
149
+ //#region src/constants/tool.ts
150
+ const ASK_USER_QUESTION_TOOL_NAME = "ask_user_question";
151
+ //#endregion
152
+ //#region src/extensions/workspaces/sessions/(backend)/tool-restriction/askUserQuestion.server.ts
153
+ var askUserQuestion_server_default$1 = (0, _agimon_ai_po_core_extensionFile.defineToolRestriction)({
154
+ when: { state: { "minor-mode": _agimon_ai_po_core_voiceTools.DOOM_VOICE_AUTO_MODE_ID } },
155
+ excludedTools: [ASK_USER_QUESTION_TOOL_NAME]
156
+ });
157
+ //#endregion
158
+ //#region src/schemas/questionnaire.ts
159
+ const OptionSchema = typebox.Type.Object({
160
+ label: typebox.Type.String({
161
+ maxLength: 60,
162
+ description: "MAX 60 CHARACTERS, hard limit. Concise option label shown to the user, ideally 1-5 words."
163
+ }),
164
+ description: typebox.Type.String({ description: "Explanation of what the option means and its important trade-offs." }),
165
+ preview: typebox.Type.Optional(typebox.Type.String({ description: "Optional markdown preview rendered while this option is focused." }))
166
+ }, { additionalProperties: false });
167
+ const QuestionSchema = typebox.Type.Object({
168
+ question: typebox.Type.String({ description: "The complete, clear question to ask the user." }),
169
+ header: typebox.Type.String({
170
+ maxLength: 16,
171
+ description: "MAX 16 CHARACTERS, short label used when navigating several questions."
172
+ }),
173
+ options: typebox.Type.Array(OptionSchema, {
174
+ minItems: 2,
175
+ maxItems: 4,
176
+ description: "The 2-4 choices offered for this question."
177
+ }),
178
+ multiSelect: typebox.Type.Optional(typebox.Type.Boolean({
179
+ description: "Allow more than one option to be selected.",
180
+ default: false
181
+ }))
182
+ }, { additionalProperties: false });
183
+ const QuestionParamsSchema = typebox.Type.Object({ questions: typebox.Type.Array(QuestionSchema, {
184
+ minItems: 1,
185
+ maxItems: 4,
186
+ description: "Questions to ask the user (1-4 questions)."
187
+ }) }, { additionalProperties: false });
188
+ function decodeAnswerEnvelope(value) {
189
+ if (value === void 0 || !value.startsWith("doom-ask-user/v1:")) return { kind: "absent" };
190
+ if (value.length > 65536) return { kind: "malformed" };
191
+ try {
192
+ return {
193
+ kind: "envelope",
194
+ payload: JSON.parse(value.slice(17))
195
+ };
196
+ } catch {
197
+ return { kind: "malformed" };
198
+ }
199
+ }
200
+ //#endregion
201
+ //#region src/services/answerEnvelope/index.ts
202
+ /**
203
+ * Read a whole-questionnaire answer envelope back against the questions it claims to answer.
204
+ *
205
+ * The envelope arrives on a select response, which is reader input rather than
206
+ * anything the tool authored, so nothing in it is taken on trust: an index has
207
+ * to name a question that was asked, a chosen label has to be one that
208
+ * question offered, and free text is capped. An envelope that fails is refused
209
+ * rather than repaired, because a half-read answer set reaches the model as
210
+ * the reader's decision and there is no way to tell from there that part of it
211
+ * was invented.
212
+ *
213
+ * `preview` is the clearest case: it is read from the option the tool
214
+ * declared, never from the wire, so the model cannot be shown a preview that
215
+ * was never offered.
216
+ *
217
+ * Host-neutral by construction: the questions and the payload both arrive as
218
+ * arguments, so the same arguments always produce the same result.
219
+ */
220
+ const MAX_ANSWER_TEXT_LENGTH = 4e3;
221
+ const ANSWER_KINDS = [
222
+ "option",
223
+ "custom",
224
+ "multi"
225
+ ];
226
+ function isRecord(value) {
227
+ return typeof value === "object" && value !== null && !Array.isArray(value);
228
+ }
229
+ function optionalNote(value) {
230
+ if (typeof value !== "string") return void 0;
231
+ const trimmed = value.trim();
232
+ return trimmed === "" ? void 0 : trimmed.slice(0, MAX_ANSWER_TEXT_LENGTH);
233
+ }
234
+ /** One answer, rebuilt from the question it names rather than copied off the wire. */
235
+ function readAnswer(entry, params, seen) {
236
+ if (!isRecord(entry)) return "an answer was not an object";
237
+ const questionIndex = entry.questionIndex;
238
+ if (typeof questionIndex !== "number" || !Number.isInteger(questionIndex)) return "an answer carried no question index";
239
+ const question = params.questions[questionIndex];
240
+ if (question === void 0) return `no question ${String(questionIndex)} was asked`;
241
+ if (seen.has(questionIndex)) return `question ${String(questionIndex)} was answered twice`;
242
+ seen.add(questionIndex);
243
+ const kind = entry.kind;
244
+ if (typeof kind !== "string" || !ANSWER_KINDS.includes(kind)) return `question ${String(questionIndex)} carried an unknown answer kind`;
245
+ const notes = optionalNote(entry.notes);
246
+ const base = {
247
+ questionIndex,
248
+ question: question.question,
249
+ ...notes === void 0 ? {} : { notes }
250
+ };
251
+ if (kind === "multi") {
252
+ const selected = entry.selected;
253
+ if (!Array.isArray(selected)) return `question ${String(questionIndex)} selected nothing readable`;
254
+ const labels = selected.filter((label) => typeof label === "string");
255
+ if (labels.length !== selected.length) return `question ${String(questionIndex)} selected a non-label`;
256
+ if (labels.some((label) => !question.options.some((option) => option.label === label))) return `question ${String(questionIndex)} selected an option it was not offered`;
257
+ return {
258
+ ...base,
259
+ kind: "multi",
260
+ answer: null,
261
+ selected: [...new Set(labels)]
262
+ };
263
+ }
264
+ if (kind === "option") {
265
+ const label = entry.answer;
266
+ const chosen = typeof label === "string" ? question.options.find((option) => option.label === label) : void 0;
267
+ if (chosen === void 0) return `question ${String(questionIndex)} chose an option it was not offered`;
268
+ return {
269
+ ...base,
270
+ kind: "option",
271
+ answer: chosen.label,
272
+ ...chosen.preview ? { preview: chosen.preview } : {}
273
+ };
274
+ }
275
+ const typed = entry.answer;
276
+ if (typeof typed !== "string") return `question ${String(questionIndex)} typed nothing readable`;
277
+ return {
278
+ ...base,
279
+ kind: "custom",
280
+ answer: typed.slice(0, MAX_ANSWER_TEXT_LENGTH)
281
+ };
282
+ }
283
+ function readAnswerEnvelope(payload, params) {
284
+ if (!isRecord(payload) || !Array.isArray(payload.answers)) return {
285
+ ok: false,
286
+ reason: "no answers were carried"
287
+ };
288
+ if (payload.answers.length === 0) return {
289
+ ok: false,
290
+ reason: "no answers were carried"
291
+ };
292
+ if (payload.answers.length > params.questions.length) return {
293
+ ok: false,
294
+ reason: "more answers than questions"
295
+ };
296
+ const seen = /* @__PURE__ */ new Set();
297
+ const answers = [];
298
+ for (const entry of payload.answers) {
299
+ const answer = readAnswer(entry, params, seen);
300
+ if (typeof answer === "string") return {
301
+ ok: false,
302
+ reason: answer
303
+ };
304
+ answers.push(answer);
305
+ }
306
+ answers.sort((left, right) => left.questionIndex - right.questionIndex);
307
+ return {
308
+ ok: true,
309
+ answers
310
+ };
311
+ }
312
+ //#endregion
313
+ //#region src/services/questionnaireService/index.ts
314
+ const CUSTOM_LABEL = "Type something.";
315
+ const DONE_LABEL = "Next";
316
+ function cancelled(answers) {
317
+ return {
318
+ answers,
319
+ cancelled: true
320
+ };
321
+ }
322
+ /** True when this response was the whole set, in which case the sink now holds the answer. */
323
+ function takeEnvelope(sink, selected) {
324
+ const read = decodeAnswerEnvelope(selected);
325
+ if (read.kind === "absent") return false;
326
+ if (read.kind === "malformed") {
327
+ sink.result = {
328
+ answers: [],
329
+ cancelled: true,
330
+ error: "malformed_answers"
331
+ };
332
+ return true;
333
+ }
334
+ const envelope = readAnswerEnvelope(read.payload, sink.params);
335
+ sink.result = envelope.ok ? {
336
+ answers: envelope.answers,
337
+ cancelled: false
338
+ } : {
339
+ answers: [],
340
+ cancelled: true,
341
+ error: "malformed_answers"
342
+ };
343
+ return true;
344
+ }
345
+ async function askForCustomAnswer(interaction, question, questionIndex, signal) {
346
+ const answer = await interaction.input(question.question, "Type your answer", signal);
347
+ if (answer === void 0) return void 0;
348
+ return {
349
+ questionIndex,
350
+ question: question.question,
351
+ kind: "custom",
352
+ answer
353
+ };
354
+ }
355
+ async function askSingleChoice(interaction, question, questionIndex, sink, signal) {
356
+ const labels = [...question.options.map((option) => option.label), CUSTOM_LABEL];
357
+ const selected = await interaction.select(question.question, labels, signal);
358
+ if (selected === void 0) return void 0;
359
+ if (takeEnvelope(sink, selected)) return void 0;
360
+ if (selected === CUSTOM_LABEL) return askForCustomAnswer(interaction, question, questionIndex, signal);
361
+ const option = question.options.find((candidate) => candidate.label === selected);
362
+ if (!option) return void 0;
363
+ return {
364
+ questionIndex,
365
+ question: question.question,
366
+ kind: "option",
367
+ answer: option.label,
368
+ ...option.preview ? { preview: option.preview } : {}
369
+ };
370
+ }
371
+ function multiChoiceLabels(question, selected) {
372
+ return [
373
+ ...question.options.map((option) => {
374
+ return `${selected.has(option.label) ? "[x]" : "[ ]"} ${option.label}`;
375
+ }),
376
+ CUSTOM_LABEL,
377
+ DONE_LABEL
378
+ ];
379
+ }
380
+ function stripSelectionMarker(value) {
381
+ return value.replace(/^\[[ x]\]\s/u, "");
382
+ }
383
+ async function askMultipleChoice(interaction, question, questionIndex, sink, signal) {
384
+ const selected = /* @__PURE__ */ new Set();
385
+ while (!signal?.aborted) {
386
+ const choice = await interaction.select(`${question.question} (choose options, then Next)`, multiChoiceLabels(question, selected), signal);
387
+ if (choice === void 0) return void 0;
388
+ if (takeEnvelope(sink, choice)) return void 0;
389
+ if (choice === CUSTOM_LABEL) return askForCustomAnswer(interaction, question, questionIndex, signal);
390
+ if (choice === DONE_LABEL) return {
391
+ questionIndex,
392
+ question: question.question,
393
+ kind: "multi",
394
+ answer: null,
395
+ selected: [...selected]
396
+ };
397
+ const label = stripSelectionMarker(choice);
398
+ if (!question.options.some((option) => option.label === label)) continue;
399
+ if (selected.has(label)) selected.delete(label);
400
+ else selected.add(label);
401
+ }
402
+ }
403
+ async function runQuestionnaire(interaction, params, signal, reportProgress) {
404
+ const answers = [];
405
+ const sink = { params };
406
+ for (let questionIndex = 0; questionIndex < params.questions.length; questionIndex += 1) {
407
+ if (signal?.aborted) return cancelled(answers);
408
+ const question = params.questions[questionIndex];
409
+ if (!question) continue;
410
+ const answer = question.multiSelect ? await askMultipleChoice(interaction, question, questionIndex, sink, signal) : await askSingleChoice(interaction, question, questionIndex, sink, signal);
411
+ if (sink.result !== void 0) {
412
+ const whole = sink.result;
413
+ if (!whole.cancelled) reportProgress?.({
414
+ ...whole,
415
+ answers: whole.answers.map((item) => ({ ...item }))
416
+ });
417
+ return whole;
418
+ }
419
+ if (!answer) return cancelled(answers);
420
+ answers.push(answer);
421
+ reportProgress?.({
422
+ answers: answers.map((item) => ({ ...item })),
423
+ cancelled: false
424
+ });
425
+ }
426
+ return {
427
+ answers,
428
+ cancelled: false
429
+ };
430
+ }
431
+ //#endregion
432
+ //#region src/services/responseService/index.ts
433
+ const DECLINE_MESSAGE = "User declined to answer questions";
434
+ const ENVELOPE_PREFIX = "User has answered your questions:";
435
+ const ENVELOPE_SUFFIX = "You can now continue with the user's answers in mind.";
436
+ const NO_INPUT_PLACEHOLDER = "(no input)";
437
+ function buildToolResult(text, details) {
438
+ return {
439
+ content: [{
440
+ type: "text",
441
+ text
442
+ }],
443
+ details
444
+ };
445
+ }
446
+ function formatAnswer(answer) {
447
+ if (answer.kind === "multi") return answer.selected && answer.selected.length > 0 ? answer.selected.join(", ") : NO_INPUT_PLACEHOLDER;
448
+ return answer.answer && answer.answer.length > 0 ? answer.answer : NO_INPUT_PLACEHOLDER;
449
+ }
450
+ function buildAnswerSegment(answer) {
451
+ const sections = [`"${answer.question}"="${formatAnswer(answer)}"`];
452
+ if (answer.preview) sections.push(`selected preview: ${answer.preview}`);
453
+ if (answer.notes) sections.push(`user notes: ${answer.notes}`);
454
+ return `${sections.join(". ")}.`;
455
+ }
456
+ function buildQuestionnaireResponse(result, params) {
457
+ if (!result || result.cancelled) return buildToolResult(DECLINE_MESSAGE, {
458
+ answers: result?.answers ?? [],
459
+ cancelled: true
460
+ });
461
+ const segments = params.questions.flatMap((_question, index) => {
462
+ const answer = result.answers.find((candidate) => candidate.questionIndex === index);
463
+ return answer ? [buildAnswerSegment(answer)] : [];
464
+ });
465
+ if (segments.length === 0) return buildToolResult(DECLINE_MESSAGE, {
466
+ answers: result.answers,
467
+ cancelled: true
468
+ });
469
+ return buildToolResult(`${ENVELOPE_PREFIX} ${segments.join(" ")} ${ENVELOPE_SUFFIX}`, result);
470
+ }
471
+ //#endregion
472
+ //#region src/services/validationService/index.ts
473
+ const ERROR_NO_QUESTIONS = "Error: At least one question is required";
474
+ const ERROR_TOO_MANY_QUESTIONS = `Error: At most 4 questions are allowed per invocation`;
475
+ const ERROR_DUPLICATE_QUESTION = "Error: Question text must be unique within an invocation";
476
+ const ERROR_TOO_FEW_OPTIONS = `Error: Each question requires at least 2 options`;
477
+ const ERROR_RESERVED_LABEL = `Error: Option label is reserved (${RESERVED_LABELS.join(", ")})`;
478
+ const ERROR_DUPLICATE_OPTION_LABEL = "Error: Option labels must be unique within a question";
479
+ const reservedLabels = new Set(RESERVED_LABELS);
480
+ function validateQuestionnaire(params) {
481
+ if (params.questions.length === 0) return {
482
+ ok: false,
483
+ error: "no_questions",
484
+ message: ERROR_NO_QUESTIONS
485
+ };
486
+ if (params.questions.length > 4) return {
487
+ ok: false,
488
+ error: "too_many_questions",
489
+ message: ERROR_TOO_MANY_QUESTIONS
490
+ };
491
+ const seenQuestions = /* @__PURE__ */ new Set();
492
+ for (const question of params.questions) {
493
+ if (seenQuestions.has(question.question)) return {
494
+ ok: false,
495
+ error: "duplicate_question",
496
+ message: ERROR_DUPLICATE_QUESTION
497
+ };
498
+ seenQuestions.add(question.question);
499
+ }
500
+ for (const question of params.questions) {
501
+ if (question.options.length < 2) return {
502
+ ok: false,
503
+ error: "empty_options",
504
+ message: ERROR_TOO_FEW_OPTIONS
505
+ };
506
+ const seenLabels = /* @__PURE__ */ new Set();
507
+ for (const option of question.options) {
508
+ if (reservedLabels.has(option.label)) return {
509
+ ok: false,
510
+ error: "reserved_label",
511
+ message: ERROR_RESERVED_LABEL
512
+ };
513
+ if (seenLabels.has(option.label)) return {
514
+ ok: false,
515
+ error: "duplicate_option_label",
516
+ message: ERROR_DUPLICATE_OPTION_LABEL
517
+ };
518
+ seenLabels.add(option.label);
519
+ }
520
+ }
521
+ return { ok: true };
522
+ }
523
+ //#endregion
524
+ //#region src/extensions/workspaces/sessions/(backend)/_tools/askUserHeadless.ts
525
+ function output(result) {
526
+ return {
527
+ content: result.content,
528
+ details: result.details
529
+ };
530
+ }
531
+ function createAskUserHeadlessTool(coordinator) {
532
+ return {
533
+ name: ASK_USER_QUESTION_TOOL_NAME,
534
+ label: "Ask User Question",
535
+ description: "Ask the user one or more structured questions during execution.",
536
+ parameters: QuestionParamsSchema,
537
+ promptSnippet: "Ask the user structured questions when requirements are ambiguous",
538
+ executionMode: "serial",
539
+ async execute(_toolCallId, parameters, signal, _onUpdate, executionContext) {
540
+ const params = parameters;
541
+ const validation = validateQuestionnaire(params);
542
+ if (!validation.ok) return output(buildToolResult(validation.message, {
543
+ answers: [],
544
+ cancelled: true,
545
+ error: validation.error
546
+ }));
547
+ const activeCoordinator = coordinator ?? new QuestionnaireCoordinator();
548
+ try {
549
+ return output(buildQuestionnaireResponse(await activeCoordinator.enqueue(async ({ signal: requestSignal, reportProgress }) => {
550
+ requestSignal.throwIfAborted();
551
+ const questionnaire = await runQuestionnaire({
552
+ select: async (title, options, interactionSignal) => {
553
+ requestSignal.throwIfAborted();
554
+ const response = await executionContext.client.request({
555
+ kind: "select",
556
+ title,
557
+ options: options.map((label) => ({
558
+ label,
559
+ value: label
560
+ }))
561
+ }, interactionSignal);
562
+ return typeof response === "string" ? response : void 0;
563
+ },
564
+ input: async (title, placeholder, interactionSignal) => {
565
+ requestSignal.throwIfAborted();
566
+ const response = await executionContext.client.request({
567
+ kind: "input",
568
+ title,
569
+ message: placeholder
570
+ }, interactionSignal);
571
+ return typeof response === "string" ? response : void 0;
572
+ }
573
+ }, params, requestSignal, reportProgress);
574
+ requestSignal.throwIfAborted();
575
+ return questionnaire;
576
+ }, signal), params));
577
+ } finally {
578
+ if (coordinator === void 0) {
579
+ activeCoordinator.shutdown();
580
+ await activeCoordinator.waitForIdle();
581
+ }
582
+ }
583
+ }
584
+ };
585
+ }
586
+ //#endregion
587
+ //#region src/extensions/workspaces/sessions/(backend)/tool/askUserQuestion.server.ts
588
+ var askUserQuestion_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerTool)((context) => createAskUserHeadlessTool(context.root.coordinator));
589
+ //#endregion
590
+ //#region generated/server.ts
591
+ const at = (value, context) => typeof value === "function" ? value(context) : value;
592
+ const via = (identity, value) => value === void 0 ? void 0 : {
593
+ ...identity,
594
+ ...value
595
+ };
596
+ const facet = (0, _agimon_ai_po_core_serverFacet.defineServerPlugin)({
597
+ name: "@agimon-ai/po-user-feedback",
598
+ providerOverrides: (0, _agimon_ai_po_core_serverFacet.composeServerProviderOverrides)(root_server_default),
599
+ session: async (context) => {
600
+ const scopeSession = await root_server_default(context);
601
+ const contextSession = {
602
+ ...context,
603
+ root: scopeSession.value
604
+ };
605
+ return {
606
+ ...(0, _agimon_ai_po_core_extensionFile.composeRootHooks)(scopeSession),
607
+ get resources() {
608
+ return [at(poUseUserFeedback_server_default, contextSession)];
609
+ },
610
+ get toolRestrictions() {
611
+ return [at(askUserQuestion_server_default$1, contextSession)];
612
+ },
613
+ get tools() {
614
+ return [via({ name: "ask_user_question" }, at(askUserQuestion_server_default, contextSession))];
615
+ },
616
+ services: [...scopeSession.services ?? []],
617
+ get activities() {
618
+ return [...scopeSession.activities ?? []];
619
+ }
620
+ };
621
+ }
622
+ });
623
+ //#endregion
624
+ exports.default = facet;
625
+ exports.facet = facet;
626
+
627
+ //# sourceMappingURL=server.cjs.map