@fungi.computer/shiitake-extensions 0.0.0-stage → 0.0.1

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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -2
  3. package/dist/almanac/contract.d.ts +213 -0
  4. package/dist/almanac/contract.js +77 -0
  5. package/dist/almanac/host.d.ts +3 -0
  6. package/dist/almanac/host.js +171 -0
  7. package/dist/goal/client.d.ts +10 -0
  8. package/dist/goal/client.js +88 -0
  9. package/dist/goal/contract.d.ts +172 -0
  10. package/dist/goal/contract.js +76 -0
  11. package/dist/goal/host.d.ts +5 -0
  12. package/dist/goal/host.js +542 -0
  13. package/dist/home/contract.d.ts +33 -0
  14. package/dist/home/contract.js +25 -0
  15. package/dist/home/host.d.ts +18 -0
  16. package/dist/home/host.js +136 -0
  17. package/dist/home/routing.d.ts +3 -0
  18. package/dist/home/routing.js +80 -0
  19. package/dist/internal/catalog.d.ts +20 -0
  20. package/dist/internal/catalog.js +33 -0
  21. package/dist/internal/cron.d.ts +5 -0
  22. package/dist/internal/cron.js +14 -0
  23. package/dist/internal/history.d.ts +29 -0
  24. package/dist/internal/history.js +41 -0
  25. package/dist/loop/client.d.ts +10 -0
  26. package/dist/loop/client.js +89 -0
  27. package/dist/loop/contract.d.ts +342 -0
  28. package/dist/loop/contract.js +94 -0
  29. package/dist/loop/host.d.ts +4 -0
  30. package/dist/loop/host.js +637 -0
  31. package/dist/plan/client.d.ts +13 -0
  32. package/dist/plan/client.js +51 -0
  33. package/dist/plan/contract.d.ts +105 -0
  34. package/dist/plan/contract.js +38 -0
  35. package/dist/plan/host.d.ts +3 -0
  36. package/dist/plan/host.js +154 -0
  37. package/dist/question/client.d.ts +10 -0
  38. package/dist/question/client.js +28 -0
  39. package/dist/question/contract.d.ts +251 -0
  40. package/dist/question/contract.js +114 -0
  41. package/dist/question/host.d.ts +3 -0
  42. package/dist/question/host.js +997 -0
  43. package/dist/roster.d.ts +9 -0
  44. package/dist/roster.js +80 -0
  45. package/dist/skills/host.d.ts +7 -0
  46. package/dist/skills/host.js +223 -0
  47. package/dist/skills/source.d.ts +28 -0
  48. package/dist/skills/source.js +1 -0
  49. package/dist/subagents/client.d.ts +10 -0
  50. package/dist/subagents/client.js +53 -0
  51. package/dist/subagents/contract.d.ts +54 -0
  52. package/dist/subagents/contract.js +38 -0
  53. package/dist/subagents/host.d.ts +50 -0
  54. package/dist/subagents/host.js +176 -0
  55. package/package.json +117 -3
@@ -0,0 +1,51 @@
1
+ import { defineClientEntry, } from "@fungi.computer/shiitake/client-entry";
2
+ import { planContract, planIsOpen } from "./contract.js";
3
+ const summary = (plan) => {
4
+ const active = plan.steps.findIndex((step) => step.status === "in_progress");
5
+ const completed = plan.steps.filter((step) => step.status === "completed").length;
6
+ const next = active < 0
7
+ ? plan.steps.find((step) => step.status === "pending")
8
+ : plan.steps[active];
9
+ return {
10
+ title: next?.step ?? "Plan complete",
11
+ detail: `${String(active < 0 ? completed : active + 1)}/${String(plan.steps.length)}`,
12
+ };
13
+ };
14
+ const rows = (plan) => plan.steps.map((step, index) => ({
15
+ id: String(index),
16
+ title: step.step,
17
+ tone: step.status === "completed"
18
+ ? "settled"
19
+ : step.status === "in_progress"
20
+ ? "running"
21
+ : "muted",
22
+ }));
23
+ /**
24
+ * Only an open plan occupies the footer, where it is inspectable and clearable;
25
+ * a finished or cleared plan hides while its committed history stays in state.
26
+ */
27
+ export default defineClientEntry(planContract, {
28
+ contribute: (view) => ({
29
+ chips: [],
30
+ panel: view.status !== "running" ||
31
+ view.value === null ||
32
+ !planIsOpen(view.value.plan)
33
+ ? []
34
+ : [
35
+ {
36
+ id: "plan",
37
+ ...summary(view.value.plan),
38
+ actions: [
39
+ { id: "plan", label: "Clear plan", input: { action: "clear" } },
40
+ ],
41
+ inspection: {
42
+ commandId: "plan",
43
+ title: "Plan",
44
+ rows: rows(view.value.plan),
45
+ },
46
+ },
47
+ ],
48
+ timeline: { cells: [], omitted: 0 },
49
+ waiting: null,
50
+ }),
51
+ });
@@ -0,0 +1,105 @@
1
+ import * as Schema from "effect/Schema";
2
+ /**
3
+ * One Session's replaceable checklist, independent of goals and loops. No
4
+ * steps means no plan: replacing it with an empty checklist clears it.
5
+ */
6
+ export declare const Plan: Schema.Struct<{
7
+ readonly explanation: Schema.optionalKey<Schema.String>;
8
+ readonly steps: Schema.$Array<Schema.Struct<{
9
+ readonly step: Schema.String;
10
+ readonly status: Schema.Literals<readonly ["pending", "in_progress", "completed"]>;
11
+ }>>;
12
+ }>;
13
+ export declare const PlanInput: Schema.Struct<{
14
+ readonly explanation: Schema.optionalKey<Schema.String>;
15
+ readonly steps: Schema.$Array<Schema.Struct<{
16
+ readonly step: Schema.String;
17
+ readonly status: Schema.Literals<readonly ["pending", "in_progress", "completed"]>;
18
+ }>>;
19
+ }>;
20
+ export type Plan = Schema.Schema.Type<typeof Plan>;
21
+ /** Open work remains: some step is not completed. Cleared and finished plans are closed. */
22
+ export declare function planIsOpen(plan: Plan): boolean;
23
+ /** The current checklist and every committed replacement, clears included. */
24
+ export declare const PlanProjection: Schema.Struct<{
25
+ readonly plan: Schema.Struct<{
26
+ readonly explanation: Schema.optionalKey<Schema.String>;
27
+ readonly steps: Schema.$Array<Schema.Struct<{
28
+ readonly step: Schema.String;
29
+ readonly status: Schema.Literals<readonly ["pending", "in_progress", "completed"]>;
30
+ }>>;
31
+ }>;
32
+ readonly history: Schema.Struct<{
33
+ readonly nextSequence: Schema.Int;
34
+ readonly omitted: Schema.Int;
35
+ readonly events: Schema.$Array<Schema.Struct<{
36
+ readonly id: Schema.String;
37
+ readonly sequence: Schema.Int;
38
+ readonly at: Schema.Int;
39
+ readonly commandId: Schema.NullOr<Schema.String>;
40
+ readonly event: Schema.Codec<{
41
+ readonly steps: readonly {
42
+ readonly step: string;
43
+ readonly status: "pending" | "completed" | "in_progress";
44
+ }[];
45
+ readonly explanation?: string;
46
+ }, {
47
+ readonly steps: readonly {
48
+ readonly step: string;
49
+ readonly status: "pending" | "completed" | "in_progress";
50
+ }[];
51
+ readonly explanation?: string;
52
+ }, never, never>;
53
+ }>>;
54
+ }>;
55
+ }>;
56
+ /** Arguments of the human `/plan` command: a bare call views, `clear` empties it. */
57
+ export declare const PlanCommandInput: Schema.Union<readonly [Schema.Struct<{
58
+ readonly action: Schema.Literal<"clear">;
59
+ }>, Schema.Struct<{}>]>;
60
+ export declare const planContract: {
61
+ id: string & import("effect/Brand").Brand<"ExtensionId">;
62
+ commands: {
63
+ plan: {
64
+ scope: "session";
65
+ input: Schema.Union<readonly [Schema.Struct<{
66
+ readonly action: Schema.Literal<"clear">;
67
+ }>, Schema.Struct<{}>]>;
68
+ output: Schema.declare<import("@fungi.computer/whistle/catalog").WhistleCatalogStepV1, import("@fungi.computer/whistle/catalog").WhistleCatalogStepV1>;
69
+ };
70
+ };
71
+ projection: {
72
+ schema: Schema.Struct<{
73
+ readonly plan: Schema.Struct<{
74
+ readonly explanation: Schema.optionalKey<Schema.String>;
75
+ readonly steps: Schema.$Array<Schema.Struct<{
76
+ readonly step: Schema.String;
77
+ readonly status: Schema.Literals<readonly ["pending", "in_progress", "completed"]>;
78
+ }>>;
79
+ }>;
80
+ readonly history: Schema.Struct<{
81
+ readonly nextSequence: Schema.Int;
82
+ readonly omitted: Schema.Int;
83
+ readonly events: Schema.$Array<Schema.Struct<{
84
+ readonly id: Schema.String;
85
+ readonly sequence: Schema.Int;
86
+ readonly at: Schema.Int;
87
+ readonly commandId: Schema.NullOr<Schema.String>;
88
+ readonly event: Schema.Codec<{
89
+ readonly steps: readonly {
90
+ readonly step: string;
91
+ readonly status: "pending" | "completed" | "in_progress";
92
+ }[];
93
+ readonly explanation?: string;
94
+ }, {
95
+ readonly steps: readonly {
96
+ readonly step: string;
97
+ readonly status: "pending" | "completed" | "in_progress";
98
+ }[];
99
+ readonly explanation?: string;
100
+ }, never, never>;
101
+ }>>;
102
+ }>;
103
+ }>;
104
+ };
105
+ };
@@ -0,0 +1,38 @@
1
+ import { historySchema } from "../internal/history.js";
2
+ import { ExtensionId, } from "@fungi.computer/shiitake/extensions";
3
+ import * as Schema from "effect/Schema";
4
+ import { CatalogStep } from "../internal/catalog.js";
5
+ /**
6
+ * One Session's replaceable checklist, independent of goals and loops. No
7
+ * steps means no plan: replacing it with an empty checklist clears it.
8
+ */
9
+ export const Plan = Schema.Struct({
10
+ explanation: Schema.optionalKey(Schema.String.pipe(Schema.check(Schema.isMaxLength(2_000)))),
11
+ steps: Schema.Array(Schema.Struct({
12
+ step: Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(500))),
13
+ status: Schema.Literals(["pending", "in_progress", "completed"]),
14
+ })).pipe(Schema.check(Schema.isMaxLength(50))),
15
+ });
16
+ export const PlanInput = Plan.pipe(Schema.check(Schema.makeFilter((plan) => plan.steps.filter((step) => step.status === "in_progress").length <=
17
+ 1 || "At most one plan step may be in progress")));
18
+ /** Open work remains: some step is not completed. Cleared and finished plans are closed. */
19
+ export function planIsOpen(plan) {
20
+ return plan.steps.some((step) => step.status !== "completed");
21
+ }
22
+ /** The current checklist and every committed replacement, clears included. */
23
+ export const PlanProjection = Schema.Struct({
24
+ plan: Plan,
25
+ history: historySchema(Plan),
26
+ });
27
+ /** Arguments of the human `/plan` command: a bare call views, `clear` empties it. */
28
+ export const PlanCommandInput = Schema.Union([
29
+ Schema.Struct({ action: Schema.Literal("clear") }),
30
+ Schema.Struct({}),
31
+ ]);
32
+ export const planContract = {
33
+ id: ExtensionId.make("botanical-session-plan"),
34
+ commands: {
35
+ plan: { scope: "session", input: PlanCommandInput, output: CatalogStep },
36
+ },
37
+ projection: { schema: PlanProjection },
38
+ };
@@ -0,0 +1,3 @@
1
+ import { type RosteredExtensionV0 } from "@fungi.computer/shiitake/extensions";
2
+ /** Durable plan owner: replace, project and advertise through core's granted doors. */
3
+ export declare const planExtension: RosteredExtensionV0;
@@ -0,0 +1,154 @@
1
+ import * as Clock from "effect/Clock";
2
+ import { appendHistory, emptyHistory, historySchema, } from "../internal/history.js";
3
+ import { Mycelium } from "@fungi.computer/mycelium";
4
+ import { defineCollection, defineExtension, ExtensionCommandError, } from "@fungi.computer/shiitake/extensions";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Option from "effect/Option";
7
+ import * as Schema from "effect/Schema";
8
+ import { z } from "zod";
9
+ import { catalog, done } from "../internal/catalog.js";
10
+ import { Plan, PlanInput, planContract, planIsOpen } from "./contract.js";
11
+ const config = Object.freeze({
12
+ promptLimit: 2_000,
13
+ guide: "Session checklist tool in execute: plan.update_plan({explanation?,steps:[{step,status:'pending'|'in_progress'|'completed'}]}). Find it with forage.search({query:'plan'}) and forage.describe. Use it for multi-step work, with at most one in-progress step; replace the whole plan on each update, and pass steps:[] to clear a plan that no longer applies. A completed checklist is not proof of goal completion.",
14
+ });
15
+ const collections = {
16
+ history: defineCollection(Schema.Struct({ sessionId: Schema.String, history: historySchema(Plan) }), { key: (row) => row.sessionId }),
17
+ plans: defineCollection(Schema.Struct({ sessionId: Schema.String, plan: Plan }), { key: (row) => row.sessionId }),
18
+ };
19
+ const input = z
20
+ .strictObject({
21
+ explanation: z.string().max(2_000).optional(),
22
+ steps: z
23
+ .array(z.strictObject({
24
+ step: z.string().min(1).max(500),
25
+ status: z.enum(["pending", "in_progress", "completed"]),
26
+ }))
27
+ .max(50),
28
+ })
29
+ .transform((value) => value.explanation === undefined
30
+ ? { steps: value.steps }
31
+ : { steps: value.steps, explanation: value.explanation });
32
+ /**
33
+ * The one write: the Agent's tool and the human's clear both replace the
34
+ * checklist here, and every distinct replacement joins the history.
35
+ */
36
+ function replacePlan(ctx, sessionId, plan, commandId) {
37
+ return Effect.gen(function* () {
38
+ const previous = Option.getOrUndefined(yield* ctx.state.plans.get(sessionId));
39
+ if (JSON.stringify(previous?.plan) !== JSON.stringify(plan)) {
40
+ const history = Option.getOrUndefined(yield* ctx.state.history.get(sessionId))
41
+ ?.history ?? emptyHistory();
42
+ yield* ctx.state.history.put({
43
+ sessionId,
44
+ history: appendHistory(history, plan, commandId, yield* Clock.currentTimeMillis),
45
+ });
46
+ yield* ctx.state.plans.put({ sessionId, plan });
47
+ }
48
+ yield* ctx.observe(sessionId);
49
+ });
50
+ }
51
+ /** Durable plan owner: replace, project and advertise through core's granted doors. */
52
+ export const planExtension = defineExtension({
53
+ id: planContract.id,
54
+ version: "2.0.0",
55
+ })
56
+ .config(config)
57
+ .state({ version: 2, migrations: {}, collections })
58
+ .define({
59
+ catalog: catalog([
60
+ {
61
+ id: "plan",
62
+ title: "Plan",
63
+ category: "Conversation",
64
+ description: "View or clear the checklist",
65
+ projections: {
66
+ help: { order: 4 },
67
+ palette: { order: 4 },
68
+ slash: {
69
+ aliases: ["plan"],
70
+ order: 4,
71
+ arguments: {
72
+ hint: "[clear]",
73
+ words: [
74
+ {
75
+ word: "clear",
76
+ description: "Clear the plan",
77
+ arguments: { action: "clear" },
78
+ },
79
+ ],
80
+ },
81
+ },
82
+ },
83
+ },
84
+ ]),
85
+ projection: {
86
+ schema: planContract.projection.schema,
87
+ read: (ctx, sessionId) => Option.map(ctx.state.plans.peek(sessionId), (row) => ({
88
+ plan: row.plan,
89
+ history: Option.getOrUndefined(ctx.state.history.peek(sessionId))?.history ??
90
+ emptyHistory(),
91
+ })),
92
+ },
93
+ prompt: (ctx, { sessionId }) => ctx.state.plans.get(sessionId).pipe(Effect.map((found) => [
94
+ {
95
+ name: "plan",
96
+ text: (ctx.config.guide +
97
+ "\n" +
98
+ (Option.isSome(found) && found.value.plan.steps.length > 0
99
+ ? JSON.stringify(found.value.plan)
100
+ : "No current plan.")).slice(0, ctx.config.promptLimit),
101
+ },
102
+ ])),
103
+ tools: (ctx, { sessionId, workId }) => Effect.succeed(Option.some(Mycelium.module({
104
+ id: "botanical.session-plan",
105
+ name: "plan",
106
+ description: "Session checklist planning tools.",
107
+ operations: {
108
+ update_plan: Mycelium.operation({
109
+ replay: "safe",
110
+ description: "Replace the Session plan checklist. At most one step in_progress; up to 50 steps; steps:[] clears the plan.",
111
+ input,
112
+ output: z.strictObject({
113
+ completed: z.number(),
114
+ total: z.number(),
115
+ }),
116
+ execute: (value) => Effect.runPromise(ctx.transact(Effect.gen(function* () {
117
+ const plan = yield* Schema.decodeUnknownEffect(PlanInput)(value).pipe(Effect.mapError(() => new ExtensionCommandError({
118
+ reason: "invalid",
119
+ message: "Invalid plan: at most one in-progress step",
120
+ })));
121
+ yield* replacePlan(ctx, sessionId, plan, workId);
122
+ return {
123
+ completed: plan.steps.filter((step) => step.status === "completed").length,
124
+ total: plan.steps.length,
125
+ };
126
+ }))),
127
+ }),
128
+ },
129
+ }))),
130
+ commands: {
131
+ specs: planContract.commands,
132
+ handlers: (ctx) => ({
133
+ plan: ({ sessionId, input }) => Effect.gen(function* () {
134
+ const plan = Option.getOrUndefined(yield* ctx.state.plans.get(sessionId))?.plan;
135
+ if (plan === undefined || plan.steps.length === 0)
136
+ return done({
137
+ type: "info",
138
+ message: "This Session has no plan.",
139
+ });
140
+ if ("action" in input) {
141
+ yield* replacePlan(ctx, sessionId, { steps: [] }, null);
142
+ return done({ type: "success", message: "Plan cleared." });
143
+ }
144
+ // An open plan's footer row opens its checklist; a finished one is hidden.
145
+ return planIsOpen(plan)
146
+ ? { type: "done" }
147
+ : done({
148
+ type: "info",
149
+ message: `Plan complete: ${String(plan.steps.length)}/${String(plan.steps.length)} steps.`,
150
+ });
151
+ }),
152
+ }),
153
+ },
154
+ });
@@ -0,0 +1,10 @@
1
+ import { type ClientContributionV1 } from "@fungi.computer/shiitake/client-entry";
2
+ /** Pending decisions use the existing footer rows and advertised answer flow. */
3
+ declare const _default: Readonly<{
4
+ protocol: "shiitake.client/v1";
5
+ id: import("@fungi.computer/shiitake/extensions").ExtensionId;
6
+ correlatedPrompts?: "note";
7
+ attach?: (context: import("@fungi.computer/shiitake/client-entry").ClientExtensionContextV1) => import("effect/Effect").Effect<void, Error, import("effect/Scope").Scope>;
8
+ contribute?: (slot: import("@fungi.computer/shiitake").ExtensionSlotV0 | undefined) => ClientContributionV1;
9
+ }>;
10
+ export default _default;
@@ -0,0 +1,28 @@
1
+ import { defineClientEntry, } from "@fungi.computer/shiitake/client-entry";
2
+ import { questionContract } from "./contract.js";
3
+ /** Pending decisions use the existing footer rows and advertised answer flow. */
4
+ export default defineClientEntry(questionContract, {
5
+ contribute: (view) => ({
6
+ chips: [],
7
+ panel: view.status !== "running" || view.value === null
8
+ ? []
9
+ : view.value.asks.map((ask) => {
10
+ const first = ask.questions[0];
11
+ return {
12
+ id: ask.askId,
13
+ title: `${first?.question ?? "Question"}${ask.questions.length > 1 ? ` (+${String(ask.questions.length - 1)} more)` : ""}`,
14
+ detail: first?.options.map((option) => option.label).join(" · ") ?? "",
15
+ tone: "attention",
16
+ actions: [
17
+ {
18
+ id: "answerFlow",
19
+ label: "Answer",
20
+ input: { askId: ask.askId },
21
+ },
22
+ ],
23
+ };
24
+ }),
25
+ timeline: { cells: [], omitted: 0 },
26
+ waiting: null,
27
+ }),
28
+ });
@@ -0,0 +1,251 @@
1
+ import * as Schema from "effect/Schema";
2
+ /** A decision question: first option is recommended, free text belongs to the host. */
3
+ export declare const Question: Schema.Struct<{
4
+ readonly id: Schema.String;
5
+ readonly header: Schema.String;
6
+ readonly question: Schema.String;
7
+ readonly options: Schema.$Array<Schema.Struct<{
8
+ readonly label: Schema.String;
9
+ readonly description: Schema.String;
10
+ }>>;
11
+ readonly multiple: Schema.optionalKey<Schema.Boolean>;
12
+ }>;
13
+ export declare const Questions: Schema.$Array<Schema.Struct<{
14
+ readonly id: Schema.String;
15
+ readonly header: Schema.String;
16
+ readonly question: Schema.String;
17
+ readonly options: Schema.$Array<Schema.Struct<{
18
+ readonly label: Schema.String;
19
+ readonly description: Schema.String;
20
+ }>>;
21
+ readonly multiple: Schema.optionalKey<Schema.Boolean>;
22
+ }>>;
23
+ export type Question = Schema.Schema.Type<typeof Question>;
24
+ /** The complete question data shared by ordinary Session clients. */
25
+ export declare const OpenAsk: Schema.Struct<{
26
+ readonly askId: Schema.String;
27
+ readonly questions: Schema.$Array<Schema.Struct<{
28
+ readonly id: Schema.String;
29
+ readonly header: Schema.String;
30
+ readonly question: Schema.String;
31
+ readonly options: Schema.$Array<Schema.Struct<{
32
+ readonly label: Schema.String;
33
+ readonly description: Schema.String;
34
+ }>>;
35
+ readonly multiple: Schema.optionalKey<Schema.Boolean>;
36
+ }>>;
37
+ readonly status: Schema.Literals<readonly ["live", "parked"]>;
38
+ readonly createdAt: Schema.Number;
39
+ readonly expiresAt: Schema.NullOr<Schema.Number>;
40
+ }>;
41
+ export type OpenAsk = Schema.Schema.Type<typeof OpenAsk>;
42
+ export declare const AskProjection: Schema.Struct<{
43
+ readonly asks: Schema.$Array<Schema.Struct<{
44
+ readonly askId: Schema.String;
45
+ readonly questions: Schema.$Array<Schema.Struct<{
46
+ readonly id: Schema.String;
47
+ readonly header: Schema.String;
48
+ readonly question: Schema.String;
49
+ readonly options: Schema.$Array<Schema.Struct<{
50
+ readonly label: Schema.String;
51
+ readonly description: Schema.String;
52
+ }>>;
53
+ readonly multiple: Schema.optionalKey<Schema.Boolean>;
54
+ }>>;
55
+ readonly status: Schema.Literals<readonly ["live", "parked"]>;
56
+ readonly createdAt: Schema.Number;
57
+ readonly expiresAt: Schema.NullOr<Schema.Number>;
58
+ }>>;
59
+ }>;
60
+ /** Stable identity for a human command and its retry. */
61
+ export declare const RequestId: Schema.String;
62
+ export declare const Answers: Schema.$Record<Schema.String, Schema.Struct<{
63
+ readonly selected: Schema.$Array<Schema.String>;
64
+ readonly text: Schema.optionalKey<Schema.String>;
65
+ }>>;
66
+ export type Answers = Schema.Schema.Type<typeof Answers>;
67
+ export declare const AnswerInput: Schema.Struct<{
68
+ readonly askId: Schema.String;
69
+ readonly requestId: Schema.String;
70
+ readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
71
+ readonly selected: Schema.$Array<Schema.String>;
72
+ readonly text: Schema.optionalKey<Schema.String>;
73
+ }>>;
74
+ }>;
75
+ export type AnswerInput = Schema.Schema.Type<typeof AnswerInput>;
76
+ export declare const DeclineInput: Schema.Struct<{
77
+ readonly askId: Schema.String;
78
+ readonly requestId: Schema.String;
79
+ readonly note: Schema.optionalKey<Schema.String>;
80
+ }>;
81
+ export type DeclineInput = Schema.Schema.Type<typeof DeclineInput>;
82
+ /** Terminal question outcomes, shared by human replies and model withdrawal. */
83
+ export declare const ClosedStatus: Schema.Literals<readonly ["answered", "declined", "withdrawn", "expired", "cancelled", "undeliverable"]>;
84
+ export declare const HumanResult: Schema.Union<readonly [Schema.Struct<{
85
+ readonly result: Schema.Literal<"accepted">;
86
+ readonly via: Schema.Literals<readonly ["in_turn", "follow_up"]>;
87
+ }>, Schema.Struct<{
88
+ readonly result: Schema.Literal<"closed">;
89
+ readonly status: Schema.Literals<readonly ["answered", "declined", "withdrawn", "expired", "cancelled", "undeliverable"]>;
90
+ }>, Schema.Struct<{
91
+ readonly result: Schema.Literal<"not_found">;
92
+ }>]>;
93
+ export type HumanResult = Schema.Schema.Type<typeof HumanResult>;
94
+ /** The ordinary /answer conversation carries its draft between typed steps. */
95
+ export declare const AnswerFlowInput: Schema.Union<readonly [Schema.Struct<{
96
+ readonly selection: Schema.String;
97
+ readonly askId: Schema.String;
98
+ readonly requestId: Schema.String;
99
+ readonly index: Schema.Number;
100
+ readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
101
+ readonly selected: Schema.$Array<Schema.String>;
102
+ readonly text: Schema.optionalKey<Schema.String>;
103
+ }>>;
104
+ readonly stage: Schema.Literal<"multiple">;
105
+ }>, Schema.Struct<{
106
+ readonly selection: Schema.String;
107
+ readonly askId: Schema.String;
108
+ readonly requestId: Schema.String;
109
+ readonly index: Schema.Number;
110
+ readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
111
+ readonly selected: Schema.$Array<Schema.String>;
112
+ readonly text: Schema.optionalKey<Schema.String>;
113
+ }>>;
114
+ readonly stage: Schema.Literal<"selection">;
115
+ }>, Schema.Struct<{
116
+ readonly selected: Schema.$Array<Schema.String>;
117
+ readonly text: Schema.String;
118
+ readonly askId: Schema.String;
119
+ readonly requestId: Schema.String;
120
+ readonly index: Schema.Number;
121
+ readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
122
+ readonly selected: Schema.$Array<Schema.String>;
123
+ readonly text: Schema.optionalKey<Schema.String>;
124
+ }>>;
125
+ readonly stage: Schema.Literal<"text">;
126
+ }>, Schema.Struct<{
127
+ readonly askId: Schema.String;
128
+ }>, Schema.Struct<{}>]>;
129
+ /** Human reads and the ordinary projection slot; model operations belong to the host. */
130
+ export declare const questionContract: {
131
+ readonly id: string & import("effect/Brand").Brand<"ExtensionId">;
132
+ readonly commands: {
133
+ readonly answerFlow: {
134
+ readonly scope: "session";
135
+ readonly input: Schema.Union<readonly [Schema.Struct<{
136
+ readonly selection: Schema.String;
137
+ readonly askId: Schema.String;
138
+ readonly requestId: Schema.String;
139
+ readonly index: Schema.Number;
140
+ readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
141
+ readonly selected: Schema.$Array<Schema.String>;
142
+ readonly text: Schema.optionalKey<Schema.String>;
143
+ }>>;
144
+ readonly stage: Schema.Literal<"multiple">;
145
+ }>, Schema.Struct<{
146
+ readonly selection: Schema.String;
147
+ readonly askId: Schema.String;
148
+ readonly requestId: Schema.String;
149
+ readonly index: Schema.Number;
150
+ readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
151
+ readonly selected: Schema.$Array<Schema.String>;
152
+ readonly text: Schema.optionalKey<Schema.String>;
153
+ }>>;
154
+ readonly stage: Schema.Literal<"selection">;
155
+ }>, Schema.Struct<{
156
+ readonly selected: Schema.$Array<Schema.String>;
157
+ readonly text: Schema.String;
158
+ readonly askId: Schema.String;
159
+ readonly requestId: Schema.String;
160
+ readonly index: Schema.Number;
161
+ readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
162
+ readonly selected: Schema.$Array<Schema.String>;
163
+ readonly text: Schema.optionalKey<Schema.String>;
164
+ }>>;
165
+ readonly stage: Schema.Literal<"text">;
166
+ }>, Schema.Struct<{
167
+ readonly askId: Schema.String;
168
+ }>, Schema.Struct<{}>]>;
169
+ readonly output: Schema.declare<import("@fungi.computer/whistle/catalog").WhistleCatalogStepV1, import("@fungi.computer/whistle/catalog").WhistleCatalogStepV1>;
170
+ };
171
+ readonly answer: {
172
+ readonly scope: "session";
173
+ readonly input: Schema.Struct<{
174
+ readonly askId: Schema.String;
175
+ readonly requestId: Schema.String;
176
+ readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
177
+ readonly selected: Schema.$Array<Schema.String>;
178
+ readonly text: Schema.optionalKey<Schema.String>;
179
+ }>>;
180
+ }>;
181
+ readonly output: Schema.Union<readonly [Schema.Struct<{
182
+ readonly result: Schema.Literal<"accepted">;
183
+ readonly via: Schema.Literals<readonly ["in_turn", "follow_up"]>;
184
+ }>, Schema.Struct<{
185
+ readonly result: Schema.Literal<"closed">;
186
+ readonly status: Schema.Literals<readonly ["answered", "declined", "withdrawn", "expired", "cancelled", "undeliverable"]>;
187
+ }>, Schema.Struct<{
188
+ readonly result: Schema.Literal<"not_found">;
189
+ }>]>;
190
+ };
191
+ readonly decline: {
192
+ readonly scope: "session";
193
+ readonly input: Schema.Struct<{
194
+ readonly askId: Schema.String;
195
+ readonly requestId: Schema.String;
196
+ readonly note: Schema.optionalKey<Schema.String>;
197
+ }>;
198
+ readonly output: Schema.Union<readonly [Schema.Struct<{
199
+ readonly result: Schema.Literal<"accepted">;
200
+ readonly via: Schema.Literals<readonly ["in_turn", "follow_up"]>;
201
+ }>, Schema.Struct<{
202
+ readonly result: Schema.Literal<"closed">;
203
+ readonly status: Schema.Literals<readonly ["answered", "declined", "withdrawn", "expired", "cancelled", "undeliverable"]>;
204
+ }>, Schema.Struct<{
205
+ readonly result: Schema.Literal<"not_found">;
206
+ }>]>;
207
+ };
208
+ readonly list: {
209
+ readonly scope: "session";
210
+ readonly input: Schema.Struct<{}>;
211
+ readonly output: Schema.Struct<{
212
+ readonly asks: Schema.$Array<Schema.Struct<{
213
+ readonly askId: Schema.String;
214
+ readonly questions: Schema.$Array<Schema.Struct<{
215
+ readonly id: Schema.String;
216
+ readonly header: Schema.String;
217
+ readonly question: Schema.String;
218
+ readonly options: Schema.$Array<Schema.Struct<{
219
+ readonly label: Schema.String;
220
+ readonly description: Schema.String;
221
+ }>>;
222
+ readonly multiple: Schema.optionalKey<Schema.Boolean>;
223
+ }>>;
224
+ readonly status: Schema.Literals<readonly ["live", "parked"]>;
225
+ readonly createdAt: Schema.Number;
226
+ readonly expiresAt: Schema.NullOr<Schema.Number>;
227
+ }>>;
228
+ }>;
229
+ };
230
+ };
231
+ readonly projection: {
232
+ readonly schema: Schema.Struct<{
233
+ readonly asks: Schema.$Array<Schema.Struct<{
234
+ readonly askId: Schema.String;
235
+ readonly questions: Schema.$Array<Schema.Struct<{
236
+ readonly id: Schema.String;
237
+ readonly header: Schema.String;
238
+ readonly question: Schema.String;
239
+ readonly options: Schema.$Array<Schema.Struct<{
240
+ readonly label: Schema.String;
241
+ readonly description: Schema.String;
242
+ }>>;
243
+ readonly multiple: Schema.optionalKey<Schema.Boolean>;
244
+ }>>;
245
+ readonly status: Schema.Literals<readonly ["live", "parked"]>;
246
+ readonly createdAt: Schema.Number;
247
+ readonly expiresAt: Schema.NullOr<Schema.Number>;
248
+ }>>;
249
+ }>;
250
+ };
251
+ };