pi-roundtable 0.19.2 → 0.21.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.
Files changed (31) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1 -1
  3. package/README.zh-TW.md +1 -1
  4. package/docs/plugins.md +51 -5
  5. package/package.json +2 -1
  6. package/src/core/discord/card-audience.ts +47 -0
  7. package/src/core/discord/owner-card-answers.ts +180 -0
  8. package/src/core/discord/owner-card-asks.ts +149 -0
  9. package/src/core/discord/owner-card-questionnaire.ts +281 -0
  10. package/src/core/discord/owner-card-rows.ts +40 -18
  11. package/src/core/discord/owner-card-types.ts +54 -5
  12. package/src/core/discord/owner-cards-fixture.ts +37 -3
  13. package/src/core/discord/owner-cards.ts +62 -133
  14. package/src/core/discord/utf16.ts +11 -0
  15. package/src/core/holds.ts +15 -2
  16. package/src/core/i18n/cards.ts +32 -2
  17. package/src/core/interactions/prompts.ts +43 -22
  18. package/src/core/interactions/questionnaire.ts +213 -0
  19. package/src/core/runtime/ask-questions.ts +93 -0
  20. package/src/core/runtime/extensions/ask-user-arguments.ts +52 -0
  21. package/src/core/runtime/extensions/ask-user-text.ts +146 -0
  22. package/src/core/runtime/extensions/ask-user.ts +87 -81
  23. package/src/core/runtime/extensions/card-ask.ts +3 -0
  24. package/src/core/runtime/extensions/confirmation-gate.ts +2 -0
  25. package/src/core/runtime/extensions/gate-refusals.ts +2 -0
  26. package/src/core/runtime/extensions/hold-lookups.ts +16 -4
  27. package/src/core/runtime/prompt-slot.ts +21 -1
  28. package/src/core/testing/surface-contract-questionnaire.ts +192 -0
  29. package/src/core/testing/surface-contract-support.ts +29 -1
  30. package/src/core/testing/surface-contract.ts +46 -20
  31. package/src/index.ts +11 -0
@@ -3,8 +3,13 @@ import type { ChatSurface } from "../contract/surface.ts";
3
3
  import { parseChannelKey } from "../contract/surface.ts";
4
4
  import type { TurnProgress } from "../domain/progress.ts";
5
5
  import type { Approval } from "../interactions/prompts.ts";
6
+ import type {
7
+ Questionnaire,
8
+ QuestionnaireAnswer,
9
+ } from "../interactions/questionnaire.ts";
6
10
  import type { ChannelKey } from "../sessions.ts";
7
11
  import type { Speaker } from "../speakers.ts";
12
+ import { QUESTIONNAIRE_CHECKS } from "./surface-contract-questionnaire.ts";
8
13
  import {
9
14
  answeredOnlyByThem,
10
15
  approval,
@@ -13,6 +18,7 @@ import {
13
18
  namedApproverAnswers,
14
19
  nextPrompt,
15
20
  type Running,
21
+ runCheck,
16
22
  scopeOf,
17
23
  seen,
18
24
  speakerOf,
@@ -44,6 +50,12 @@ export interface SurfaceContractSubject {
44
50
  observations(): readonly SurfaceObservation[];
45
51
  /** The person answers an open approval; without it the prompt checks are skipped. */
46
52
  answer?(prompt: string, approved: boolean): Promise<void>;
53
+ /** The person answers an open questionnaire, as shaped for `asks`; without it those checks are skipped. */
54
+ answerQuestionnaire?(
55
+ prompt: string,
56
+ answer: QuestionnaireAnswer,
57
+ questionnaire: Questionnaire,
58
+ ): Promise<void>;
47
59
  /**
48
60
  * The person as the speaker of the turns that ask them, given to `surface.prompts` as the
49
61
  * scope `promptScope(speaker, visibility)`; default an owner-tier speaker. Every approval the
@@ -71,6 +83,12 @@ export interface SurfaceContractSubject {
71
83
  * named-approver checks are skipped.
72
84
  */
73
85
  approver?: SurfaceContractAnswerer & { principalId: string };
86
+ /**
87
+ * Set by a surface that honours `ApprovalOptions.speakerOnly` in a shared conversation, where
88
+ * `owner` is on the network and could otherwise answer: the owner's answer to such an approval
89
+ * settles nothing, the person's does. Without it, or without `owner`, the check is skipped.
90
+ */
91
+ speakerOnly?: boolean;
74
92
  /**
75
93
  * Set by a surface that serves only conversations private to one person, such as the web chat:
76
94
  * it has no shared conversation in which an approval is the named approvers', so it skips that
@@ -85,6 +103,12 @@ export interface SurfaceContractAnswerer {
85
103
  /** They join the surface, once it has started. */
86
104
  join?(): Promise<void>;
87
105
  answer(prompt: string, approved: boolean): Promise<void>;
106
+ /** They answer an open questionnaire; without it its stranger check is skipped. */
107
+ answerQuestionnaire?(
108
+ prompt: string,
109
+ answer: QuestionnaireAnswer,
110
+ questionnaire: Questionnaire,
111
+ ): Promise<void>;
88
112
  }
89
113
 
90
114
  /** One way the subject broke the contract. */
@@ -351,6 +375,23 @@ const CHECKS: readonly Check[] = [
351
375
  run: (running) =>
352
376
  answeredOnlyByThem(running, running.subject.owner, "private"),
353
377
  },
378
+ {
379
+ name: "an approval that is the speaker's alone is not answered by an owner in a shared conversation",
380
+ applies: (subject) =>
381
+ subject.surface.prompts !== undefined &&
382
+ subject.answer !== undefined &&
383
+ subject.owner !== undefined &&
384
+ subject.speakerOnly === true &&
385
+ subject.privateOnly !== true,
386
+ run: (running) =>
387
+ answeredOnlyByThem(
388
+ running,
389
+ running.subject.owner,
390
+ "shared",
391
+ undefined,
392
+ true,
393
+ ),
394
+ },
354
395
  {
355
396
  name: "a named approver answers an approval instead of the person; the person and another person cannot",
356
397
  applies: (subject) =>
@@ -401,26 +442,9 @@ const CHECKS: readonly Check[] = [
401
442
  );
402
443
  },
403
444
  },
445
+ ...QUESTIONNAIRE_CHECKS,
404
446
  ];
405
447
 
406
- async function runCheck(
407
- check: Check,
408
- make: () => Promise<SurfaceContractSubject>,
409
- ): Promise<"passed" | "skipped"> {
410
- const subject = await make();
411
- const running: Running = { subject, delivered: [] };
412
- try {
413
- if (check.applies && !check.applies(subject)) return "skipped";
414
- await subject.surface.start((message) => running.delivered.push(message));
415
- await subject.join?.();
416
- await check.run(running);
417
- return "passed";
418
- } finally {
419
- await subject.close?.();
420
- await subject.surface.stop?.();
421
- }
422
- }
423
-
424
448
  /**
425
449
  * Runs the chat surface contract on fresh subjects from `make`, one per check, and returns the
426
450
  * checks the surface broke. `describeSurfaceContract` registers the same checks as tests.
@@ -447,9 +471,11 @@ export async function checkSurfaceContract(
447
471
  * one its plugin withdraws (`ApprovalOptions.supersede`) as cancelled, ignores
448
472
  * another person's answer to the person's approval, and, in a private conversation, an owner's
449
473
  * too, and lets an approval above the person's tier there come back at once, shown to no one.
450
- * Where it can name approvers, an approval that does is answered by them, reported as the
474
+ * Where `speakerOnly` is declared, an approval that is the speaker's alone is not settled by an
475
+ * owner's answer in a shared conversation. Where it can name approvers, an approval that does is answered by them, reported as the
451
476
  * approver, and not by the person or another person, and a private conversation's is answered by
452
- * its person alone, whoever the call names besides them. Each
477
+ * its person alone, whoever the call names besides them. A subject that gives
478
+ * `answerQuestionnaire` must declare `asks`, and then questionnaires keep the same rules. Each
453
479
  * check gets a fresh subject from `make`; a check for an optional part the surface lacks passes.
454
480
  */
455
481
  export function describeSurfaceContract(
package/src/index.ts CHANGED
@@ -195,6 +195,7 @@ export type {
195
195
  ApprovalOptions,
196
196
  ApprovedBy,
197
197
  AskOption,
198
+ AskSupport,
198
199
  LateAnswer,
199
200
  OwnerAnswer,
200
201
  OwnerPrompts,
@@ -202,8 +203,18 @@ export type {
202
203
  PromptScope,
203
204
  Prompts,
204
205
  PromptWait,
206
+ Questionnaire,
207
+ QuestionnaireAnswer,
205
208
  } from "./core/interactions/prompts.ts";
206
209
  export { promptScope, withdrawalNote } from "./core/interactions/prompts.ts";
210
+ export {
211
+ checkAnswer,
212
+ checkQuestionnaireAnswer,
213
+ QUESTIONNAIRE_LIMITS,
214
+ SINGLE_QUESTION,
215
+ shapeFor,
216
+ validateQuestionnaire,
217
+ } from "./core/interactions/questionnaire.ts";
207
218
  export type { JudgeModel } from "./core/judging/model-judge.ts";
208
219
  export type { LogEntry, LogFn, Logger } from "./core/log.ts";
209
220
  export type { ThinkingLevel, ThinkingSetting } from "./core/models.ts";