@fungi.computer/shiitake-extensions 0.3.0 → 0.5.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.
- package/README.md +20 -16
- package/dist/goal/contract.d.ts +6 -0
- package/dist/goal/contract.js +6 -0
- package/dist/goal/host.js +183 -31
- package/dist/loop/contract.d.ts +136 -2
- package/dist/loop/contract.js +45 -2
- package/dist/loop/host.js +23 -0
- package/dist/question/answer-flow.d.ts +27 -0
- package/dist/question/answer-flow.js +115 -0
- package/dist/question/client.d.ts +1 -1
- package/dist/question/client.js +22 -3
- package/dist/question/contract.d.ts +202 -60
- package/dist/question/contract.js +78 -22
- package/dist/question/host.d.ts +4 -0
- package/dist/question/host.js +348 -339
- package/dist/roster/conversation-agents.d.ts +21 -1
- package/dist/roster/conversation-agents.js +47 -2
- package/dist/roster.d.ts +5 -2
- package/dist/roster.js +16 -5
- package/dist/schedules.d.ts +178 -0
- package/dist/schedules.js +182 -0
- package/dist/subagents/client.js +64 -20
- package/dist/subagents/contract.d.ts +123 -10
- package/dist/subagents/contract.js +38 -5
- package/dist/subagents/host.d.ts +2 -4
- package/dist/subagents/host.js +152 -22
- package/docs/api/README.md +1 -0
- package/docs/api/goal/contract.md +1 -1
- package/docs/api/goal/host.md +22 -1
- package/docs/api/loop/contract.md +43 -31
- package/docs/api/question/client.md +2 -1
- package/docs/api/question/contract.md +183 -51
- package/docs/api/question/host.md +30 -0
- package/docs/api/roster/conversation-agents.md +34 -8
- package/docs/api/roster.md +39 -2
- package/docs/api/schedules.md +481 -0
- package/docs/api/subagents/contract.md +101 -28
- package/docs/api/subagents/host.md +5 -3
- package/package.json +9 -6
package/dist/loop/host.js
CHANGED
|
@@ -281,6 +281,13 @@ function fire(ctx, sessionId, dueAt, now) {
|
|
|
281
281
|
delivery: "followUp",
|
|
282
282
|
},
|
|
283
283
|
}));
|
|
284
|
+
// The Agent owner will pause this loop after flipping its archive flag.
|
|
285
|
+
// If this timer wins that short interval, keep the loop resumable instead
|
|
286
|
+
// of treating an intentional archive refusal as a permanent failed run.
|
|
287
|
+
if (Result.isFailure(admitted) && admitted.failure.reason === "archived") {
|
|
288
|
+
yield* arm(ctx, { ...loop, lastError: admitted.failure.message }, now + 30_000);
|
|
289
|
+
return yield* ctx.observe(sessionId);
|
|
290
|
+
}
|
|
284
291
|
if (Result.isFailure(admitted) || admitted.success._tag === "NotReady") {
|
|
285
292
|
yield* commitLoop(ctx, {
|
|
286
293
|
...loop,
|
|
@@ -493,6 +500,14 @@ function stopLoop(ctx, sessionId, reason) {
|
|
|
493
500
|
return projected(stopped);
|
|
494
501
|
});
|
|
495
502
|
}
|
|
503
|
+
/** Match and mutate within the same extension command transaction. */
|
|
504
|
+
function controlIdentifiedLoop(ctx, target, action) {
|
|
505
|
+
return requireLoop(ctx, target.sessionId).pipe(Effect.flatMap((loop) => loop.loopId !== target.loopId
|
|
506
|
+
? Effect.fail(conflict("Session loop has been replaced"))
|
|
507
|
+
: action === "pause"
|
|
508
|
+
? pauseLoop(ctx, target.sessionId)
|
|
509
|
+
: stopLoop(ctx, target.sessionId)));
|
|
510
|
+
}
|
|
496
511
|
function cronForInterval(value, unit) {
|
|
497
512
|
if (unit === "m" || unit === "min")
|
|
498
513
|
return value > 59 ? undefined : `0 */${String(value)} * * * *`;
|
|
@@ -662,6 +677,14 @@ export const loopExtension = defineExtension({
|
|
|
662
677
|
commands: {
|
|
663
678
|
specs: loopContract.commands,
|
|
664
679
|
handlers: (ctx) => ({
|
|
680
|
+
pauseLoop: ({ input }) => controlIdentifiedLoop(ctx, input, "pause"),
|
|
681
|
+
stopLoop: ({ input }) => controlIdentifiedLoop(ctx, input, "stop"),
|
|
682
|
+
list: ({ input }) => ctx.state.loops
|
|
683
|
+
.page({ after: input.after, limit: input.limit ?? 64 })
|
|
684
|
+
.pipe(Effect.map((rows) => rows.map((row) => ({
|
|
685
|
+
...projected(row),
|
|
686
|
+
sessionId: row.sessionId,
|
|
687
|
+
})))),
|
|
665
688
|
startSelfPaced: ({ sessionId, input }) => start(ctx, sessionId, input, null),
|
|
666
689
|
startFixedInterval: ({ sessionId, input }) => start(ctx, sessionId, input, {
|
|
667
690
|
expression: input.expression,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { WhistleCatalogStepV1 } from "@fungi.computer/whistle/catalog";
|
|
2
|
+
import { ExtensionCommandError } from "@fungi.computer/shiitake/extensions";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import { type Answers, type AnswerFlowInput, type Question } from "./contract.js";
|
|
5
|
+
import type * as Schema from "effect/Schema";
|
|
6
|
+
/** Drafts travel in catalog arguments; only an owner's answer commits them. */
|
|
7
|
+
export type FlowInput = Schema.Schema.Type<typeof AnswerFlowInput>;
|
|
8
|
+
/** What the answer conversation does next for one open Ask. */
|
|
9
|
+
export type AnswerFlowOutcome = Readonly<{
|
|
10
|
+
type: "step";
|
|
11
|
+
step: WhistleCatalogStepV1;
|
|
12
|
+
}> | Readonly<{
|
|
13
|
+
type: "complete";
|
|
14
|
+
askId: string;
|
|
15
|
+
requestId: string;
|
|
16
|
+
answers: Answers;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Progress one Ask's answer draft by a single human step. The owner of the
|
|
20
|
+
* Ask commits a completed set; a step only ever returns the next prompt, so
|
|
21
|
+
* the same conversation serves the Ask's own Session and a parent's footer.
|
|
22
|
+
*/
|
|
23
|
+
export declare function advanceAnswerFlow(row: Readonly<{
|
|
24
|
+
askId: string;
|
|
25
|
+
questions: readonly Question[];
|
|
26
|
+
closed: boolean;
|
|
27
|
+
}>, input: FlowInput): Effect.Effect<AnswerFlowOutcome, ExtensionCommandError>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { ExtensionCommandError } from "@fungi.computer/shiitake/extensions";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { ask, done, freshRequestId } from "../internal/catalog.js";
|
|
4
|
+
import { titleLimit } from "../internal/headline.js";
|
|
5
|
+
import {} from "./contract.js";
|
|
6
|
+
/** Accept only picks the question offered, and a non-empty answer. */
|
|
7
|
+
function decisionAnswer(question, answer) {
|
|
8
|
+
const offered = new Set(question.options.map((option) => option.label));
|
|
9
|
+
const written = answer.text?.trim() ?? "";
|
|
10
|
+
if (answer.selected.some((label) => !offered.has(label)) ||
|
|
11
|
+
new Set(answer.selected).size !== answer.selected.length ||
|
|
12
|
+
(question.multiple !== true && answer.selected.length > 1) ||
|
|
13
|
+
(answer.selected.length === 0 && written === ""))
|
|
14
|
+
return Effect.fail(new ExtensionCommandError({
|
|
15
|
+
reason: "invalid",
|
|
16
|
+
message: "Choose offered options or write an answer",
|
|
17
|
+
}));
|
|
18
|
+
return Effect.succeed(written === ""
|
|
19
|
+
? { selected: answer.selected }
|
|
20
|
+
: { selected: answer.selected, text: answer.text ?? "" });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The Agent's own words are the title only when they fit one; a longer
|
|
24
|
+
* question gets a plain title and sits in the body, whole in the details.
|
|
25
|
+
*/
|
|
26
|
+
function questionHeading(question) {
|
|
27
|
+
const text = question.question.replace(/\s+/gu, " ").trim();
|
|
28
|
+
if (text.length <= titleLimit)
|
|
29
|
+
return { message: text };
|
|
30
|
+
return {
|
|
31
|
+
message: "The Agent has a question",
|
|
32
|
+
body: question.question.slice(0, 4_000),
|
|
33
|
+
bodyLabel: "Question",
|
|
34
|
+
details: [{ label: "Question", value: question.question.slice(0, 4_000) }],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function promptQuestion(nextQuestion, next, total) {
|
|
38
|
+
const base = {
|
|
39
|
+
type: "decision",
|
|
40
|
+
...questionHeading(nextQuestion),
|
|
41
|
+
options: nextQuestion.options.map((option) => ({
|
|
42
|
+
value: option.label,
|
|
43
|
+
label: option.label,
|
|
44
|
+
description: option.description,
|
|
45
|
+
})),
|
|
46
|
+
other: {
|
|
47
|
+
label: "Other…",
|
|
48
|
+
placeholder: "Write your own answer",
|
|
49
|
+
maxLength: 4_000,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
// Only present fields travel: the wire is JSON, which has no undefined.
|
|
53
|
+
const numbered = total > 1
|
|
54
|
+
? {
|
|
55
|
+
...base,
|
|
56
|
+
summary: `Question ${String(next.index + 1)} of ${String(total)}`,
|
|
57
|
+
}
|
|
58
|
+
: base;
|
|
59
|
+
return ask(nextQuestion.multiple === true ? { ...numbered, multiple: true } : numbered, { stage: "decision", ...next }, "answer");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Progress one Ask's answer draft by a single human step. The owner of the
|
|
63
|
+
* Ask commits a completed set; a step only ever returns the next prompt, so
|
|
64
|
+
* the same conversation serves the Ask's own Session and a parent's footer.
|
|
65
|
+
*/
|
|
66
|
+
export function advanceAnswerFlow(row, input) {
|
|
67
|
+
return Effect.gen(function* () {
|
|
68
|
+
const draft = "stage" in input
|
|
69
|
+
? input
|
|
70
|
+
: {
|
|
71
|
+
stage: "start",
|
|
72
|
+
index: 0,
|
|
73
|
+
requestId: yield* freshRequestId,
|
|
74
|
+
answers: {},
|
|
75
|
+
};
|
|
76
|
+
let { index, answers } = draft;
|
|
77
|
+
const { requestId } = draft;
|
|
78
|
+
const question = row.questions[index];
|
|
79
|
+
if (question === undefined)
|
|
80
|
+
return yield* Effect.fail(new ExtensionCommandError({
|
|
81
|
+
reason: "invalid",
|
|
82
|
+
message: "Unknown question step",
|
|
83
|
+
}));
|
|
84
|
+
const answer = draft.stage === "decision"
|
|
85
|
+
? yield* decisionAnswer(question, draft.answer)
|
|
86
|
+
: undefined;
|
|
87
|
+
if (answer !== undefined) {
|
|
88
|
+
answers = { ...answers, [question.id]: answer };
|
|
89
|
+
index += 1;
|
|
90
|
+
if (index === row.questions.length)
|
|
91
|
+
return {
|
|
92
|
+
type: "complete",
|
|
93
|
+
askId: row.askId,
|
|
94
|
+
requestId,
|
|
95
|
+
answers,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (row.closed)
|
|
99
|
+
return {
|
|
100
|
+
type: "step",
|
|
101
|
+
step: done({
|
|
102
|
+
type: "info",
|
|
103
|
+
message: "That question is already closed.",
|
|
104
|
+
}),
|
|
105
|
+
};
|
|
106
|
+
const next = { askId: row.askId, requestId, index, answers };
|
|
107
|
+
const nextQuestion = row.questions[index];
|
|
108
|
+
if (nextQuestion === undefined)
|
|
109
|
+
throw new Error("Expected the next question");
|
|
110
|
+
return {
|
|
111
|
+
type: "step",
|
|
112
|
+
step: promptQuestion(nextQuestion, next, row.questions.length),
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ClientContributionV1 } from "@fungi.computer/shiitake/client-entry";
|
|
2
|
-
/** Pending decisions
|
|
2
|
+
/** Pending decisions take over the composer; the footer row is where a postponed one waits. */
|
|
3
3
|
declare const _default: Readonly<{
|
|
4
4
|
protocol: "shiitake.client/v1";
|
|
5
5
|
id: import("@fungi.computer/shiitake/extensions").ExtensionId;
|
package/dist/question/client.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineClientEntry, } from "@fungi.computer/shiitake/client-entry";
|
|
2
2
|
import { questionContract } from "./contract.js";
|
|
3
|
-
/** Pending decisions
|
|
3
|
+
/** Pending decisions take over the composer; the footer row is where a postponed one waits. */
|
|
4
4
|
export default defineClientEntry(questionContract, {
|
|
5
5
|
contribute: (view) => ({
|
|
6
6
|
chips: [],
|
|
@@ -8,16 +8,35 @@ export default defineClientEntry(questionContract, {
|
|
|
8
8
|
? []
|
|
9
9
|
: view.value.asks.map((ask) => {
|
|
10
10
|
const first = ask.questions[0];
|
|
11
|
+
const title = `${first?.question ?? "Question"}${ask.questions.length > 1 ? ` (+${String(ask.questions.length - 1)} more)` : ""}`;
|
|
12
|
+
const detail = first?.options.map((option) => option.label).join(" · ") ?? "";
|
|
13
|
+
// An ask waiting on an Agent is calm: it never takes over the
|
|
14
|
+
// composer, but a person may still answer it first.
|
|
15
|
+
if (ask.waitingOn !== undefined)
|
|
16
|
+
return {
|
|
17
|
+
id: ask.askId,
|
|
18
|
+
title: `waiting on ${ask.waitingOn.name} · ${title}`,
|
|
19
|
+
detail,
|
|
20
|
+
tone: "muted",
|
|
21
|
+
actions: [
|
|
22
|
+
{
|
|
23
|
+
id: "answerFlow",
|
|
24
|
+
label: "Answer",
|
|
25
|
+
input: { askId: ask.askId },
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
11
29
|
return {
|
|
12
30
|
id: ask.askId,
|
|
13
|
-
title
|
|
14
|
-
detail
|
|
31
|
+
title,
|
|
32
|
+
detail,
|
|
15
33
|
tone: "attention",
|
|
16
34
|
actions: [
|
|
17
35
|
{
|
|
18
36
|
id: "answerFlow",
|
|
19
37
|
label: "Answer",
|
|
20
38
|
input: { askId: ask.askId },
|
|
39
|
+
awaiting: "question",
|
|
21
40
|
},
|
|
22
41
|
],
|
|
23
42
|
};
|
|
@@ -41,6 +41,16 @@ export type Question = Schema.Schema.Type<typeof Question>;
|
|
|
41
41
|
export declare const OpenAsk: Schema.Struct<{
|
|
42
42
|
/** Durable identity of the open ask. */
|
|
43
43
|
readonly askId: Schema.String;
|
|
44
|
+
/**
|
|
45
|
+
* The Agent this ask waits on first, derived by the host from whom the
|
|
46
|
+
* asking run's work came from. Absent means a person. An ask waiting on an
|
|
47
|
+
* Agent is calm: the Agent answers it or escalates it to a person.
|
|
48
|
+
*/
|
|
49
|
+
readonly waitingOn: Schema.optionalKey<Schema.Struct<{
|
|
50
|
+
readonly agentId: Schema.NonEmptyString;
|
|
51
|
+
readonly sessionId: Schema.NonEmptyString;
|
|
52
|
+
readonly name: Schema.NonEmptyString;
|
|
53
|
+
}>>;
|
|
44
54
|
/** Decisions awaiting the person's answers. */
|
|
45
55
|
readonly questions: Schema.$Array<Schema.Struct<{
|
|
46
56
|
/** Identity used to associate this question with its answer. */
|
|
@@ -74,6 +84,16 @@ export declare const AskProjection: Schema.Struct<{
|
|
|
74
84
|
readonly asks: Schema.$Array<Schema.Struct<{
|
|
75
85
|
/** Durable identity of the open ask. */
|
|
76
86
|
readonly askId: Schema.String;
|
|
87
|
+
/**
|
|
88
|
+
* The Agent this ask waits on first, derived by the host from whom the
|
|
89
|
+
* asking run's work came from. Absent means a person. An ask waiting on an
|
|
90
|
+
* Agent is calm: the Agent answers it or escalates it to a person.
|
|
91
|
+
*/
|
|
92
|
+
readonly waitingOn: Schema.optionalKey<Schema.Struct<{
|
|
93
|
+
readonly agentId: Schema.NonEmptyString;
|
|
94
|
+
readonly sessionId: Schema.NonEmptyString;
|
|
95
|
+
readonly name: Schema.NonEmptyString;
|
|
96
|
+
}>>;
|
|
77
97
|
/** Decisions awaiting the person's answers. */
|
|
78
98
|
readonly questions: Schema.$Array<Schema.Struct<{
|
|
79
99
|
/** Identity used to associate this question with its answer. */
|
|
@@ -146,6 +166,8 @@ export declare const HumanResult: Schema.Union<readonly [Schema.Struct<{
|
|
|
146
166
|
readonly result: Schema.Literal<"accepted">;
|
|
147
167
|
/** Whether the reply resumed its turn or became a follow-up. */
|
|
148
168
|
readonly via: Schema.Literals<readonly ["in_turn", "follow_up"]>;
|
|
169
|
+
/** The follow-up command carrying the reply, when it became one. */
|
|
170
|
+
readonly commandId: Schema.optionalKey<Schema.String>;
|
|
149
171
|
}>, Schema.Struct<{
|
|
150
172
|
/** Ask had already reached a terminal state. */
|
|
151
173
|
readonly result: Schema.Literal<"closed">;
|
|
@@ -157,40 +179,80 @@ export declare const HumanResult: Schema.Union<readonly [Schema.Struct<{
|
|
|
157
179
|
}>]>;
|
|
158
180
|
/** Decoded outcome of a human answer or decline. */
|
|
159
181
|
export type HumanResult = Schema.Schema.Type<typeof HumanResult>;
|
|
160
|
-
/**
|
|
161
|
-
export declare const
|
|
162
|
-
/**
|
|
163
|
-
readonly
|
|
164
|
-
|
|
165
|
-
readonly
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
readonly
|
|
182
|
+
/** Only the Agent an Ask waits on may answer or escalate it. */
|
|
183
|
+
export declare const SenderRefusal: Schema.Struct<{
|
|
184
|
+
/** The caller is not the Agent this Ask waits on. */
|
|
185
|
+
readonly result: Schema.Literal<"refused">;
|
|
186
|
+
/** Explains why the Agent's response cannot be applied. */
|
|
187
|
+
readonly reason: Schema.Literal<"not_sender">;
|
|
188
|
+
}>;
|
|
189
|
+
/** Outcome of the Agent an Ask waits on answering it. */
|
|
190
|
+
export declare const AgentAnswerResult: Schema.Union<readonly [Schema.Union<readonly [Schema.Struct<{
|
|
191
|
+
/** Reply was accepted. */
|
|
192
|
+
readonly result: Schema.Literal<"accepted">;
|
|
193
|
+
/** Whether the reply resumed its turn or became a follow-up. */
|
|
194
|
+
readonly via: Schema.Literals<readonly ["in_turn", "follow_up"]>;
|
|
195
|
+
/** The follow-up command carrying the reply, when it became one. */
|
|
196
|
+
readonly commandId: Schema.optionalKey<Schema.String>;
|
|
197
|
+
}>, Schema.Struct<{
|
|
198
|
+
/** Ask had already reached a terminal state. */
|
|
199
|
+
readonly result: Schema.Literal<"closed">;
|
|
200
|
+
/** Terminal state that prevented another answer. */
|
|
201
|
+
readonly status: Schema.Literals<readonly ["answered", "declined", "withdrawn", "expired", "cancelled", "undeliverable"]>;
|
|
175
202
|
}>, Schema.Struct<{
|
|
176
|
-
/**
|
|
177
|
-
readonly
|
|
203
|
+
/** No ask with this identity exists. */
|
|
204
|
+
readonly result: Schema.Literal<"not_found">;
|
|
205
|
+
}>]>, Schema.Struct<{
|
|
206
|
+
/** The caller is not the Agent this Ask waits on. */
|
|
207
|
+
readonly result: Schema.Literal<"refused">;
|
|
208
|
+
/** Explains why the Agent's response cannot be applied. */
|
|
209
|
+
readonly reason: Schema.Literal<"not_sender">;
|
|
210
|
+
}>]>;
|
|
211
|
+
/** Decoded result of an authenticated Agent answer. */
|
|
212
|
+
export type AgentAnswerResult = Schema.Schema.Type<typeof AgentAnswerResult>;
|
|
213
|
+
/** The Agent that answered, as the host authenticated it. */
|
|
214
|
+
export declare const AnsweredBy: Schema.Struct<{
|
|
215
|
+
/** Identifies an Agent, never a person. */
|
|
216
|
+
readonly kind: Schema.Literal<"agent">;
|
|
217
|
+
/** Stable identity of the authenticated Agent. */
|
|
218
|
+
readonly agentId: Schema.String;
|
|
219
|
+
}>;
|
|
220
|
+
/** Outcome of the Agent an Ask waits on passing it on. */
|
|
221
|
+
export declare const EscalateResult: Schema.Union<readonly [Schema.Struct<{
|
|
222
|
+
/** The Ask now waits on someone else. */
|
|
223
|
+
readonly result: Schema.Literal<"escalated">;
|
|
224
|
+
/** Whom it waits on now: a person. */
|
|
225
|
+
readonly to: Schema.Literal<"person">;
|
|
226
|
+
}>, Schema.Struct<{
|
|
227
|
+
/** Ask had already reached a terminal state. */
|
|
228
|
+
readonly result: Schema.Literal<"closed">;
|
|
229
|
+
/** Terminal state that prevented the escalation. */
|
|
230
|
+
readonly status: Schema.Literals<readonly ["answered", "declined", "withdrawn", "expired", "cancelled", "undeliverable"]>;
|
|
231
|
+
}>, Schema.Struct<{
|
|
232
|
+
/** No ask with this identity exists. */
|
|
233
|
+
readonly result: Schema.Literal<"not_found">;
|
|
234
|
+
}>, Schema.Struct<{
|
|
235
|
+
/** The caller is not the Agent this Ask waits on. */
|
|
236
|
+
readonly result: Schema.Literal<"refused">;
|
|
237
|
+
/** Explains why the Agent's response cannot be applied. */
|
|
238
|
+
readonly reason: Schema.Literal<"not_sender">;
|
|
239
|
+
}>]>;
|
|
240
|
+
/** Decoded result of passing an Ask on. */
|
|
241
|
+
export type EscalateResult = Schema.Schema.Type<typeof EscalateResult>;
|
|
242
|
+
/** The Agent's request to pass an Ask on; the caller is host context. */
|
|
243
|
+
export declare const EscalateInput: Schema.Struct<{
|
|
244
|
+
/** Ask being passed on. */
|
|
178
245
|
readonly askId: Schema.String;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
246
|
+
}>;
|
|
247
|
+
/** The answer conversation carries its draft between decision steps. */
|
|
248
|
+
export declare const AnswerFlowInput: Schema.Union<readonly [Schema.Struct<{
|
|
249
|
+
/** The person's picks and optional written answer for question `index`. */
|
|
250
|
+
readonly answer: Schema.Struct<{
|
|
182
251
|
/** Labels of the offered choices selected by the person. */
|
|
183
252
|
readonly selected: Schema.$Array<Schema.String>;
|
|
184
253
|
/** Optional free-text answer supplied by the person. */
|
|
185
254
|
readonly text: Schema.optionalKey<Schema.String>;
|
|
186
|
-
}
|
|
187
|
-
/** Single-choice selection step. */
|
|
188
|
-
readonly stage: Schema.Literal<"selection">;
|
|
189
|
-
}>, Schema.Struct<{
|
|
190
|
-
/** Offered choices retained while entering free text. */
|
|
191
|
-
readonly selected: Schema.$Array<Schema.String>;
|
|
192
|
-
/** Free-text answer supplied by the person. */
|
|
193
|
-
readonly text: Schema.String;
|
|
255
|
+
}>;
|
|
194
256
|
readonly askId: Schema.String;
|
|
195
257
|
readonly requestId: Schema.String;
|
|
196
258
|
readonly index: Schema.Number;
|
|
@@ -200,8 +262,8 @@ export declare const AnswerFlowInput: Schema.Union<readonly [Schema.Struct<{
|
|
|
200
262
|
/** Optional free-text answer supplied by the person. */
|
|
201
263
|
readonly text: Schema.optionalKey<Schema.String>;
|
|
202
264
|
}>>;
|
|
203
|
-
/**
|
|
204
|
-
readonly stage: Schema.Literal<"
|
|
265
|
+
/** One decision answered in the composer. */
|
|
266
|
+
readonly stage: Schema.Literal<"decision">;
|
|
205
267
|
}>, Schema.Struct<{
|
|
206
268
|
/** Ask whose answer conversation should be opened. */
|
|
207
269
|
readonly askId: Schema.String;
|
|
@@ -218,38 +280,13 @@ export declare const questionContract: {
|
|
|
218
280
|
readonly scope: "session";
|
|
219
281
|
/** Decode the current answer-draft step. */
|
|
220
282
|
readonly input: Schema.Union<readonly [Schema.Struct<{
|
|
221
|
-
/**
|
|
222
|
-
readonly
|
|
223
|
-
readonly askId: Schema.String;
|
|
224
|
-
readonly requestId: Schema.String;
|
|
225
|
-
readonly index: Schema.Number;
|
|
226
|
-
readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
|
|
283
|
+
/** The person's picks and optional written answer for question `index`. */
|
|
284
|
+
readonly answer: Schema.Struct<{
|
|
227
285
|
/** Labels of the offered choices selected by the person. */
|
|
228
286
|
readonly selected: Schema.$Array<Schema.String>;
|
|
229
287
|
/** Optional free-text answer supplied by the person. */
|
|
230
288
|
readonly text: Schema.optionalKey<Schema.String>;
|
|
231
|
-
}
|
|
232
|
-
/** Multiple-choice selection step. */
|
|
233
|
-
readonly stage: Schema.Literal<"multiple">;
|
|
234
|
-
}>, Schema.Struct<{
|
|
235
|
-
/** Encoded selection supplied by the human control. */
|
|
236
|
-
readonly selection: Schema.String;
|
|
237
|
-
readonly askId: Schema.String;
|
|
238
|
-
readonly requestId: Schema.String;
|
|
239
|
-
readonly index: Schema.Number;
|
|
240
|
-
readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
|
|
241
|
-
/** Labels of the offered choices selected by the person. */
|
|
242
|
-
readonly selected: Schema.$Array<Schema.String>;
|
|
243
|
-
/** Optional free-text answer supplied by the person. */
|
|
244
|
-
readonly text: Schema.optionalKey<Schema.String>;
|
|
245
|
-
}>>;
|
|
246
|
-
/** Single-choice selection step. */
|
|
247
|
-
readonly stage: Schema.Literal<"selection">;
|
|
248
|
-
}>, Schema.Struct<{
|
|
249
|
-
/** Offered choices retained while entering free text. */
|
|
250
|
-
readonly selected: Schema.$Array<Schema.String>;
|
|
251
|
-
/** Free-text answer supplied by the person. */
|
|
252
|
-
readonly text: Schema.String;
|
|
289
|
+
}>;
|
|
253
290
|
readonly askId: Schema.String;
|
|
254
291
|
readonly requestId: Schema.String;
|
|
255
292
|
readonly index: Schema.Number;
|
|
@@ -259,8 +296,8 @@ export declare const questionContract: {
|
|
|
259
296
|
/** Optional free-text answer supplied by the person. */
|
|
260
297
|
readonly text: Schema.optionalKey<Schema.String>;
|
|
261
298
|
}>>;
|
|
262
|
-
/**
|
|
263
|
-
readonly stage: Schema.Literal<"
|
|
299
|
+
/** One decision answered in the composer. */
|
|
300
|
+
readonly stage: Schema.Literal<"decision">;
|
|
264
301
|
}>, Schema.Struct<{
|
|
265
302
|
/** Ask whose answer conversation should be opened. */
|
|
266
303
|
readonly askId: Schema.String;
|
|
@@ -292,6 +329,8 @@ export declare const questionContract: {
|
|
|
292
329
|
readonly result: Schema.Literal<"accepted">;
|
|
293
330
|
/** Whether the reply resumed its turn or became a follow-up. */
|
|
294
331
|
readonly via: Schema.Literals<readonly ["in_turn", "follow_up"]>;
|
|
332
|
+
/** The follow-up command carrying the reply, when it became one. */
|
|
333
|
+
readonly commandId: Schema.optionalKey<Schema.String>;
|
|
295
334
|
}>, Schema.Struct<{
|
|
296
335
|
/** Ask had already reached a terminal state. */
|
|
297
336
|
readonly result: Schema.Literal<"closed">;
|
|
@@ -302,6 +341,87 @@ export declare const questionContract: {
|
|
|
302
341
|
readonly result: Schema.Literal<"not_found">;
|
|
303
342
|
}>]>;
|
|
304
343
|
};
|
|
344
|
+
/** Submit the answer of the Agent this Ask waits on; never a human answer. */
|
|
345
|
+
readonly answerAgent: {
|
|
346
|
+
/** The child Session owns the Ask; caller authority is host context. */
|
|
347
|
+
readonly scope: "session";
|
|
348
|
+
/** Decode the answer submission without any caller-supplied actor. */
|
|
349
|
+
readonly input: Schema.Struct<{
|
|
350
|
+
/** Ask being answered. */
|
|
351
|
+
readonly askId: Schema.String;
|
|
352
|
+
/** Stable identity shared by this command and its retries. */
|
|
353
|
+
readonly requestId: Schema.String;
|
|
354
|
+
/** Answers to the ask's question set. */
|
|
355
|
+
readonly answers: Schema.$Record<Schema.String, Schema.Struct<{
|
|
356
|
+
/** Labels of the offered choices selected by the person. */
|
|
357
|
+
readonly selected: Schema.$Array<Schema.String>;
|
|
358
|
+
/** Optional free-text answer supplied by the person. */
|
|
359
|
+
readonly text: Schema.optionalKey<Schema.String>;
|
|
360
|
+
}>>;
|
|
361
|
+
}>;
|
|
362
|
+
/** Attribute the accepted answer to its authenticated Agent. */
|
|
363
|
+
readonly output: Schema.Struct<{
|
|
364
|
+
/** Whether the answer was accepted, or why not. */
|
|
365
|
+
readonly result: Schema.Union<readonly [Schema.Union<readonly [Schema.Struct<{
|
|
366
|
+
/** Reply was accepted. */
|
|
367
|
+
readonly result: Schema.Literal<"accepted">;
|
|
368
|
+
/** Whether the reply resumed its turn or became a follow-up. */
|
|
369
|
+
readonly via: Schema.Literals<readonly ["in_turn", "follow_up"]>;
|
|
370
|
+
/** The follow-up command carrying the reply, when it became one. */
|
|
371
|
+
readonly commandId: Schema.optionalKey<Schema.String>;
|
|
372
|
+
}>, Schema.Struct<{
|
|
373
|
+
/** Ask had already reached a terminal state. */
|
|
374
|
+
readonly result: Schema.Literal<"closed">;
|
|
375
|
+
/** Terminal state that prevented another answer. */
|
|
376
|
+
readonly status: Schema.Literals<readonly ["answered", "declined", "withdrawn", "expired", "cancelled", "undeliverable"]>;
|
|
377
|
+
}>, Schema.Struct<{
|
|
378
|
+
/** No ask with this identity exists. */
|
|
379
|
+
readonly result: Schema.Literal<"not_found">;
|
|
380
|
+
}>]>, Schema.Struct<{
|
|
381
|
+
/** The caller is not the Agent this Ask waits on. */
|
|
382
|
+
readonly result: Schema.Literal<"refused">;
|
|
383
|
+
/** Explains why the Agent's response cannot be applied. */
|
|
384
|
+
readonly reason: Schema.Literal<"not_sender">;
|
|
385
|
+
}>]>;
|
|
386
|
+
/** The authenticated Agent that answered. */
|
|
387
|
+
readonly answeredBy: Schema.Struct<{
|
|
388
|
+
/** Identifies an Agent, never a person. */
|
|
389
|
+
readonly kind: Schema.Literal<"agent">;
|
|
390
|
+
/** Stable identity of the authenticated Agent. */
|
|
391
|
+
readonly agentId: Schema.String;
|
|
392
|
+
}>;
|
|
393
|
+
}>;
|
|
394
|
+
};
|
|
395
|
+
/** Pass the Ask on from the Agent it waits on; never a human action. */
|
|
396
|
+
readonly escalateAgent: {
|
|
397
|
+
/** The child Session owns the Ask; caller authority is host context. */
|
|
398
|
+
readonly scope: "session";
|
|
399
|
+
/** Decode the escalation without any caller-supplied recipient. */
|
|
400
|
+
readonly input: Schema.Struct<{
|
|
401
|
+
/** Ask being passed on. */
|
|
402
|
+
readonly askId: Schema.String;
|
|
403
|
+
}>;
|
|
404
|
+
/** Where the Ask waits now, or why it did not move. */
|
|
405
|
+
readonly output: Schema.Union<readonly [Schema.Struct<{
|
|
406
|
+
/** The Ask now waits on someone else. */
|
|
407
|
+
readonly result: Schema.Literal<"escalated">;
|
|
408
|
+
/** Whom it waits on now: a person. */
|
|
409
|
+
readonly to: Schema.Literal<"person">;
|
|
410
|
+
}>, Schema.Struct<{
|
|
411
|
+
/** Ask had already reached a terminal state. */
|
|
412
|
+
readonly result: Schema.Literal<"closed">;
|
|
413
|
+
/** Terminal state that prevented the escalation. */
|
|
414
|
+
readonly status: Schema.Literals<readonly ["answered", "declined", "withdrawn", "expired", "cancelled", "undeliverable"]>;
|
|
415
|
+
}>, Schema.Struct<{
|
|
416
|
+
/** No ask with this identity exists. */
|
|
417
|
+
readonly result: Schema.Literal<"not_found">;
|
|
418
|
+
}>, Schema.Struct<{
|
|
419
|
+
/** The caller is not the Agent this Ask waits on. */
|
|
420
|
+
readonly result: Schema.Literal<"refused">;
|
|
421
|
+
/** Explains why the Agent's response cannot be applied. */
|
|
422
|
+
readonly reason: Schema.Literal<"not_sender">;
|
|
423
|
+
}>]>;
|
|
424
|
+
};
|
|
305
425
|
/** Decline an ask with an optional note. */
|
|
306
426
|
readonly decline: {
|
|
307
427
|
/** The Session owns this ask. */
|
|
@@ -321,6 +441,8 @@ export declare const questionContract: {
|
|
|
321
441
|
readonly result: Schema.Literal<"accepted">;
|
|
322
442
|
/** Whether the reply resumed its turn or became a follow-up. */
|
|
323
443
|
readonly via: Schema.Literals<readonly ["in_turn", "follow_up"]>;
|
|
444
|
+
/** The follow-up command carrying the reply, when it became one. */
|
|
445
|
+
readonly commandId: Schema.optionalKey<Schema.String>;
|
|
324
446
|
}>, Schema.Struct<{
|
|
325
447
|
/** Ask had already reached a terminal state. */
|
|
326
448
|
readonly result: Schema.Literal<"closed">;
|
|
@@ -343,6 +465,16 @@ export declare const questionContract: {
|
|
|
343
465
|
readonly asks: Schema.$Array<Schema.Struct<{
|
|
344
466
|
/** Durable identity of the open ask. */
|
|
345
467
|
readonly askId: Schema.String;
|
|
468
|
+
/**
|
|
469
|
+
* The Agent this ask waits on first, derived by the host from whom the
|
|
470
|
+
* asking run's work came from. Absent means a person. An ask waiting on an
|
|
471
|
+
* Agent is calm: the Agent answers it or escalates it to a person.
|
|
472
|
+
*/
|
|
473
|
+
readonly waitingOn: Schema.optionalKey<Schema.Struct<{
|
|
474
|
+
readonly agentId: Schema.NonEmptyString;
|
|
475
|
+
readonly sessionId: Schema.NonEmptyString;
|
|
476
|
+
readonly name: Schema.NonEmptyString;
|
|
477
|
+
}>>;
|
|
346
478
|
/** Decisions awaiting the person's answers. */
|
|
347
479
|
readonly questions: Schema.$Array<Schema.Struct<{
|
|
348
480
|
/** Identity used to associate this question with its answer. */
|
|
@@ -379,6 +511,16 @@ export declare const questionContract: {
|
|
|
379
511
|
readonly asks: Schema.$Array<Schema.Struct<{
|
|
380
512
|
/** Durable identity of the open ask. */
|
|
381
513
|
readonly askId: Schema.String;
|
|
514
|
+
/**
|
|
515
|
+
* The Agent this ask waits on first, derived by the host from whom the
|
|
516
|
+
* asking run's work came from. Absent means a person. An ask waiting on an
|
|
517
|
+
* Agent is calm: the Agent answers it or escalates it to a person.
|
|
518
|
+
*/
|
|
519
|
+
readonly waitingOn: Schema.optionalKey<Schema.Struct<{
|
|
520
|
+
readonly agentId: Schema.NonEmptyString;
|
|
521
|
+
readonly sessionId: Schema.NonEmptyString;
|
|
522
|
+
readonly name: Schema.NonEmptyString;
|
|
523
|
+
}>>;
|
|
382
524
|
/** Decisions awaiting the person's answers. */
|
|
383
525
|
readonly questions: Schema.$Array<Schema.Struct<{
|
|
384
526
|
/** Identity used to associate this question with its answer. */
|