@nyte-ai/plugin 0.0.25-nightly.20261102.45 → 0.0.27
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/THIRD-PARTY-NOTICES.md +65 -0
- package/dist/chunks/{bash-description-myvnmtt2.js → bash-description-03bm07ft.js} +2 -8
- package/dist/chunks/{bash-description-9q5rxbtt.js → bash-description-0gnxcq7q.js} +31 -11
- package/dist/chunks/bash-description-0vfhp1qd.js +54 -0
- package/dist/chunks/{bash-description-g7gfy7nw.js → bash-description-4kqkzdkp.js} +3 -5
- package/dist/chunks/{bash-description-axnga0jz.js → bash-description-a99pev5h.js} +2 -2
- package/dist/chunks/{bash-description-bkhr9zrz.js → bash-description-s6v2m3ch.js} +28 -10
- package/dist/chunks/{bash-description-qwyy182r.js → bash-description-spc5av5d.js} +1 -7
- package/dist/chunks/bash-description-t3hbavcc.js +12 -0
- package/dist/src/acp/connection.js +1 -1
- package/dist/src/acp/index.js +2 -2
- package/dist/src/acp/transcript.js +1 -1
- package/dist/src/approvals/approvals.js +6 -3
- package/dist/src/approvals/schema.js +1 -1
- package/dist/src/browser-client.d.ts +135 -0
- package/dist/src/browser-client.js +374 -0
- package/dist/src/canvas/canvas-client.d.ts +71 -0
- package/dist/src/canvas/canvas-client.js +70 -0
- package/dist/src/canvas/canvas-compile.d.ts +0 -34
- package/dist/src/canvas/canvas-libraries.d.ts +0 -6
- package/dist/src/canvas/canvas-preview.d.ts +0 -65
- package/dist/src/canvas/canvas-protocol.d.ts +5 -80
- package/dist/src/canvas/canvas.d.ts +0 -25
- package/dist/src/canvas/schema.d.ts +0 -37
- package/dist/src/client/notifications.js +2 -1
- package/dist/src/client/presentation.d.ts +3 -23
- package/dist/src/client/presentation.js +7 -3
- package/dist/src/client/transcript.js +18 -18
- package/dist/src/client/user-messages.d.ts +41 -0
- package/dist/src/client/user-messages.js +10 -0
- package/dist/src/desktop-settings/desktop-settings.d.ts +31 -0
- package/dist/src/desktop-settings/desktop-settings.js +136 -0
- package/dist/src/desktop-settings/schema.d.ts +42 -0
- package/dist/src/desktop-settings/schema.js +14 -0
- package/dist/src/question/client/questions-tui.js +6 -2
- package/dist/src/question/client/questions.js +47 -46
- package/dist/src/question/question.d.ts +37 -6
- package/dist/src/question/question.js +69 -17
- package/dist/src/question/schema.d.ts +73 -11
- package/dist/src/question/schema.js +9 -5
- package/dist/src/rename.d.ts +1 -1
- package/dist/src/subagents.js +11 -23
- package/dist/src/web/fetch.js +1 -1
- package/dist/src/web/index.js +1 -1
- package/package.json +30 -14
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import type { Static } from "typebox";
|
|
3
|
+
/** How a chat's state can reach you past its sidebar mark, which always shows. */
|
|
4
|
+
export declare const ALERT_CHANNELS: readonly ["notification", "badge", "sound", "bounce", "remind"];
|
|
5
|
+
export type AlertChannel = (typeof ALERT_CHANNELS)[number];
|
|
6
|
+
/** The states that alert, each with the channels it offers. Working only marks the sidebar. */
|
|
7
|
+
export declare const ALERT_OFFERS: {
|
|
8
|
+
readonly waiting: readonly ["notification", "badge", "sound", "bounce", "remind"];
|
|
9
|
+
readonly failed: readonly ["notification", "badge", "sound", "bounce"];
|
|
10
|
+
readonly done: readonly ["notification", "badge", "sound"];
|
|
11
|
+
};
|
|
12
|
+
export type AlertState = keyof typeof ALERT_OFFERS;
|
|
13
|
+
/** The desktop setting holding each state's chosen channels. */
|
|
14
|
+
export declare const ALERT_SETTING: {
|
|
15
|
+
readonly waiting: "alertsWaiting";
|
|
16
|
+
readonly failed: "alertsFailed";
|
|
17
|
+
readonly done: "alertsDone";
|
|
18
|
+
};
|
|
19
|
+
/** Settings the desktop's main and host processes read; the app reads and writes them as `desktop.<key>`. */
|
|
20
|
+
export declare const DESKTOP_SETTING_SCHEMAS: {
|
|
21
|
+
keepAwake: Type.TBoolean;
|
|
22
|
+
pauseOnSleep: Type.TBoolean;
|
|
23
|
+
terminalShell: Type.TUnion<[Type.TString, Type.TNull]>;
|
|
24
|
+
blockAds: Type.TBoolean;
|
|
25
|
+
adblockAllowedHosts: Type.TArray<Type.TString>;
|
|
26
|
+
upgradeToHttps: Type.TBoolean;
|
|
27
|
+
webOrigins: Type.TArray<Type.TString>;
|
|
28
|
+
notifications: Type.TBoolean;
|
|
29
|
+
dockBadge: Type.TBoolean;
|
|
30
|
+
notificationSounds: Type.TBoolean;
|
|
31
|
+
alertsWaiting: Type.TArray<Type.TEnum<["notification", "badge", "sound", "bounce", "remind"]>>;
|
|
32
|
+
alertsFailed: Type.TArray<Type.TEnum<["notification", "badge", "sound", "bounce"]>>;
|
|
33
|
+
alertsDone: Type.TArray<Type.TEnum<["notification", "badge", "sound"]>>;
|
|
34
|
+
remindMinutes: Type.TUnion<[Type.TLiteral<1>, Type.TLiteral<2>, Type.TLiteral<5>, Type.TLiteral<15>]>;
|
|
35
|
+
notifyViewedChat: Type.TBoolean;
|
|
36
|
+
notifySubagents: Type.TBoolean;
|
|
37
|
+
terminalNotifications: Type.TBoolean;
|
|
38
|
+
};
|
|
39
|
+
export type DesktopSettings = {
|
|
40
|
+
readonly [K in keyof typeof DESKTOP_SETTING_SCHEMAS]: Static<(typeof DESKTOP_SETTING_SCHEMAS)[K]>;
|
|
41
|
+
};
|
|
42
|
+
export declare const DEFAULT_DESKTOP_SETTINGS: DesktopSettings;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ALERT_CHANNELS2,
|
|
3
|
+
ALERT_OFFERS2,
|
|
4
|
+
ALERT_SETTING2,
|
|
5
|
+
DESKTOP_SETTING_SCHEMAS2,
|
|
6
|
+
DEFAULT_DESKTOP_SETTINGS2
|
|
7
|
+
} from "../../chunks/bash-description-0vfhp1qd.js";
|
|
8
|
+
export {
|
|
9
|
+
ALERT_CHANNELS2 as ALERT_CHANNELS,
|
|
10
|
+
ALERT_OFFERS2 as ALERT_OFFERS,
|
|
11
|
+
ALERT_SETTING2 as ALERT_SETTING,
|
|
12
|
+
DEFAULT_DESKTOP_SETTINGS2 as DEFAULT_DESKTOP_SETTINGS,
|
|
13
|
+
DESKTOP_SETTING_SCHEMAS2 as DESKTOP_SETTING_SCHEMAS
|
|
14
|
+
};
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
question2
|
|
3
|
-
} from "../../../chunks/bash-description-
|
|
3
|
+
} from "../../../chunks/bash-description-s6v2m3ch.js";
|
|
4
4
|
|
|
5
5
|
// src/question/client/questions-tui.ts
|
|
6
6
|
import { Box, Text } from "@opentui/core";
|
|
7
7
|
import { defineRenderer } from "@nyte-ai/plugin/client";
|
|
8
8
|
var unreadable = (kind) => Text({ content: `This ${kind} part cannot be shown.` });
|
|
9
9
|
var questionRenderers = [
|
|
10
|
-
defineRenderer(question2, "tui", (state) => Box({ border: true, title: "Questions", flexDirection: "column" }, ...state.questions.map((item, index) => Box({ flexDirection: "column" }, Text({ content: `${item.header}: ${item.question}` }), ...item.options.map((option) => Text({ content: `${option.label}: ${option.description}` })), ...state.
|
|
10
|
+
defineRenderer(question2, "tui", (state) => Box({ border: true, title: "Questions", flexDirection: "column" }, ...state.questions.map((item, index) => Box({ flexDirection: "column" }, Text({ content: `${item.header}: ${item.question}` }), ...item.options.map((option) => Text({ content: `${option.label}: ${option.description}` })), ...state.phase.kind === "answered" ? [
|
|
11
|
+
Text({
|
|
12
|
+
content: `Answer: ${state.phase.answers[index].join(", ") || "Unanswered"}`
|
|
13
|
+
})
|
|
14
|
+
] : state.phase.kind === "skipped" ? [Text({ content: "Skipped" })] : []))), unreadable)
|
|
11
15
|
];
|
|
12
16
|
var questions_tui_default = {
|
|
13
17
|
id: "questions-tui",
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
question2
|
|
3
|
-
} from "../../../chunks/bash-description-
|
|
3
|
+
} from "../../../chunks/bash-description-s6v2m3ch.js";
|
|
4
4
|
|
|
5
5
|
// src/question/client/questions.tsx
|
|
6
6
|
import { useId, useRef, useState } from "react";
|
|
7
7
|
import { defineRenderer } from "@nyte-ai/plugin/client";
|
|
8
|
-
import {
|
|
9
|
-
var unreadable = (kind) => /* @__PURE__ */
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
var unreadable = (kind) => /* @__PURE__ */ jsxs("div", {
|
|
10
10
|
"data-part": kind,
|
|
11
11
|
children: [
|
|
12
12
|
"This ",
|
|
13
13
|
kind,
|
|
14
14
|
" part cannot be shown."
|
|
15
15
|
]
|
|
16
|
-
}
|
|
16
|
+
});
|
|
17
17
|
function QuestionForm({
|
|
18
18
|
questions,
|
|
19
19
|
act
|
|
@@ -47,7 +47,7 @@ function QuestionForm({
|
|
|
47
47
|
}
|
|
48
48
|
submitting.current = false;
|
|
49
49
|
};
|
|
50
|
-
return /* @__PURE__ */
|
|
50
|
+
return /* @__PURE__ */ jsxs("form", {
|
|
51
51
|
"data-part": "ask/question",
|
|
52
52
|
"aria-label": "Questions",
|
|
53
53
|
onSubmit: (event) => {
|
|
@@ -55,18 +55,18 @@ function QuestionForm({
|
|
|
55
55
|
submit();
|
|
56
56
|
},
|
|
57
57
|
children: [
|
|
58
|
-
questions.map((item, index) => /* @__PURE__ */
|
|
58
|
+
questions.map((item, index) => /* @__PURE__ */ jsxs("fieldset", {
|
|
59
59
|
disabled: blocked,
|
|
60
60
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
61
|
+
/* @__PURE__ */ jsx("legend", {
|
|
62
62
|
children: item.header
|
|
63
|
-
}
|
|
64
|
-
/* @__PURE__ */
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ jsx("p", {
|
|
65
65
|
children: item.question
|
|
66
|
-
}
|
|
67
|
-
item.options.map((option) => /* @__PURE__ */
|
|
66
|
+
}),
|
|
67
|
+
item.options.map((option) => /* @__PURE__ */ jsxs("label", {
|
|
68
68
|
children: [
|
|
69
|
-
/* @__PURE__ */
|
|
69
|
+
/* @__PURE__ */ jsx("input", {
|
|
70
70
|
type: item.multiple ? "checkbox" : "radio",
|
|
71
71
|
name: `${id}-${index}`,
|
|
72
72
|
value: option.label,
|
|
@@ -82,19 +82,19 @@ function QuestionForm({
|
|
|
82
82
|
if (!item.multiple)
|
|
83
83
|
setCustom((current) => current.map((typed, position) => position === index ? "" : typed));
|
|
84
84
|
}
|
|
85
|
-
}
|
|
86
|
-
/* @__PURE__ */
|
|
85
|
+
}),
|
|
86
|
+
/* @__PURE__ */ jsx("span", {
|
|
87
87
|
children: option.label
|
|
88
|
-
}
|
|
89
|
-
/* @__PURE__ */
|
|
88
|
+
}),
|
|
89
|
+
/* @__PURE__ */ jsx("span", {
|
|
90
90
|
children: option.description
|
|
91
|
-
}
|
|
91
|
+
})
|
|
92
92
|
]
|
|
93
|
-
}, option.label
|
|
94
|
-
/* @__PURE__ */
|
|
93
|
+
}, option.label)),
|
|
94
|
+
/* @__PURE__ */ jsxs("label", {
|
|
95
95
|
children: [
|
|
96
96
|
"Type your own answer",
|
|
97
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ jsx("textarea", {
|
|
98
98
|
value: custom[index],
|
|
99
99
|
onChange: ({ currentTarget }) => {
|
|
100
100
|
const typed = currentTarget.value;
|
|
@@ -102,55 +102,56 @@ function QuestionForm({
|
|
|
102
102
|
if (!item.multiple && typed.trim() !== "")
|
|
103
103
|
setSelected((current) => current.map((choices, position) => position === index ? [] : choices));
|
|
104
104
|
}
|
|
105
|
-
}
|
|
105
|
+
})
|
|
106
106
|
]
|
|
107
|
-
}
|
|
107
|
+
})
|
|
108
108
|
]
|
|
109
|
-
}, index
|
|
110
|
-
/* @__PURE__ */
|
|
109
|
+
}, index)),
|
|
110
|
+
/* @__PURE__ */ jsx("button", {
|
|
111
111
|
type: "submit",
|
|
112
112
|
disabled: blocked,
|
|
113
113
|
children: status.kind === "sending" ? "Sending answers…" : "Submit answers"
|
|
114
|
-
}
|
|
115
|
-
status.kind === "failed" && /* @__PURE__ */
|
|
114
|
+
}),
|
|
115
|
+
status.kind === "failed" && /* @__PURE__ */ jsx("p", {
|
|
116
116
|
role: "alert",
|
|
117
117
|
children: status.message
|
|
118
|
-
}
|
|
119
|
-
status.kind === "sent" && /* @__PURE__ */
|
|
118
|
+
}),
|
|
119
|
+
status.kind === "sent" && /* @__PURE__ */ jsx("p", {
|
|
120
120
|
role: "status",
|
|
121
121
|
children: "Answers sent."
|
|
122
|
-
}
|
|
122
|
+
})
|
|
123
123
|
]
|
|
124
|
-
}
|
|
124
|
+
});
|
|
125
125
|
}
|
|
126
126
|
var questionRenderers = [
|
|
127
127
|
defineRenderer(question2, "react", (state, act) => {
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
130
|
-
return /* @__PURE__ */
|
|
128
|
+
const phase = state.phase;
|
|
129
|
+
if (phase.kind === "answered" || phase.kind === "skipped")
|
|
130
|
+
return /* @__PURE__ */ jsx("div", {
|
|
131
131
|
"data-part": "ask/question",
|
|
132
132
|
"aria-label": "Answers",
|
|
133
|
-
children: state.questions.map((item, index) => /* @__PURE__ */
|
|
133
|
+
children: state.questions.map((item, index) => /* @__PURE__ */ jsxs("section", {
|
|
134
134
|
children: [
|
|
135
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ jsx("h3", {
|
|
136
136
|
children: item.header
|
|
137
|
-
}
|
|
138
|
-
/* @__PURE__ */
|
|
137
|
+
}),
|
|
138
|
+
/* @__PURE__ */ jsx("p", {
|
|
139
139
|
children: item.question
|
|
140
|
-
}
|
|
141
|
-
/* @__PURE__ */
|
|
140
|
+
}),
|
|
141
|
+
/* @__PURE__ */ jsxs("p", {
|
|
142
142
|
children: [
|
|
143
|
-
"Answer:
|
|
144
|
-
|
|
143
|
+
"Answer:",
|
|
144
|
+
" ",
|
|
145
|
+
phase.kind === "answered" ? phase.answers[index].join(", ") || "Unanswered" : "Skipped"
|
|
145
146
|
]
|
|
146
|
-
}
|
|
147
|
+
})
|
|
147
148
|
]
|
|
148
|
-
}, index
|
|
149
|
-
}
|
|
150
|
-
return /* @__PURE__ */
|
|
149
|
+
}, index))
|
|
150
|
+
});
|
|
151
|
+
return /* @__PURE__ */ jsx(QuestionForm, {
|
|
151
152
|
questions: state.questions,
|
|
152
153
|
act
|
|
153
|
-
}, JSON.stringify(state.questions)
|
|
154
|
+
}, JSON.stringify(state.questions));
|
|
154
155
|
}, unreadable)
|
|
155
156
|
];
|
|
156
157
|
var questions_default = { id: "questions", contribute: { renderers: questionRenderers } };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ToolDefinition } from "@nyte-ai/core";
|
|
2
2
|
export declare const question: import("@nyte-ai/core").PartDefinition<{
|
|
3
|
+
call: import("@nyte-ai/schema").Id<"call">;
|
|
3
4
|
questions: {
|
|
4
5
|
question: string;
|
|
5
6
|
header: string;
|
|
@@ -9,17 +10,33 @@ export declare const question: import("@nyte-ai/core").PartDefinition<{
|
|
|
9
10
|
}[];
|
|
10
11
|
multiple?: boolean | undefined;
|
|
11
12
|
}[];
|
|
12
|
-
|
|
13
|
+
phase: {
|
|
14
|
+
kind: "asking";
|
|
15
|
+
} | {
|
|
16
|
+
kind: "open";
|
|
17
|
+
head: import("@nyte-ai/schema").Id<"head">;
|
|
18
|
+
} | {
|
|
19
|
+
kind: "answered";
|
|
20
|
+
answers: string[][];
|
|
21
|
+
head: import("@nyte-ai/schema").Id<"head"> | null;
|
|
22
|
+
} | {
|
|
23
|
+
kind: "skipped";
|
|
24
|
+
late: boolean;
|
|
25
|
+
};
|
|
13
26
|
}, {
|
|
14
27
|
answer: {
|
|
15
28
|
input: import("@nyte-ai/schema").Schema<{
|
|
16
29
|
answers: string[][];
|
|
17
30
|
}>;
|
|
18
31
|
};
|
|
32
|
+
skip: {
|
|
33
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
34
|
+
};
|
|
19
35
|
}>;
|
|
20
36
|
/**
|
|
21
37
|
* Contributes the question tool and its grouped modal. The durable wait
|
|
22
|
-
* resumes after one complete submission from any client
|
|
38
|
+
* resumes after one complete submission or a skip from any client, or after
|
|
39
|
+
* a minute; an answer after that reaches the asking head as a message.
|
|
23
40
|
*
|
|
24
41
|
* @category plugins
|
|
25
42
|
* @since 0.1.0
|
|
@@ -28,6 +45,7 @@ declare const _default: {
|
|
|
28
45
|
id: string;
|
|
29
46
|
contribute: {
|
|
30
47
|
parts: import("@nyte-ai/core").PartDefinition<{
|
|
48
|
+
call: import("@nyte-ai/schema").Id<"call">;
|
|
31
49
|
questions: {
|
|
32
50
|
question: string;
|
|
33
51
|
header: string;
|
|
@@ -37,13 +55,28 @@ declare const _default: {
|
|
|
37
55
|
}[];
|
|
38
56
|
multiple?: boolean | undefined;
|
|
39
57
|
}[];
|
|
40
|
-
|
|
58
|
+
phase: {
|
|
59
|
+
kind: "asking";
|
|
60
|
+
} | {
|
|
61
|
+
kind: "open";
|
|
62
|
+
head: import("@nyte-ai/schema").Id<"head">;
|
|
63
|
+
} | {
|
|
64
|
+
kind: "answered";
|
|
65
|
+
answers: string[][];
|
|
66
|
+
head: import("@nyte-ai/schema").Id<"head"> | null;
|
|
67
|
+
} | {
|
|
68
|
+
kind: "skipped";
|
|
69
|
+
late: boolean;
|
|
70
|
+
};
|
|
41
71
|
}, {
|
|
42
72
|
answer: {
|
|
43
73
|
input: import("@nyte-ai/schema").Schema<{
|
|
44
74
|
answers: string[][];
|
|
45
75
|
}>;
|
|
46
76
|
};
|
|
77
|
+
skip: {
|
|
78
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
79
|
+
};
|
|
47
80
|
}>[];
|
|
48
81
|
tools: ToolDefinition<{
|
|
49
82
|
questions: {
|
|
@@ -55,9 +88,7 @@ declare const _default: {
|
|
|
55
88
|
}[];
|
|
56
89
|
multiple?: boolean | undefined;
|
|
57
90
|
}[];
|
|
58
|
-
},
|
|
59
|
-
answers: string[][] | null;
|
|
60
|
-
}>[];
|
|
91
|
+
}, unknown>[];
|
|
61
92
|
};
|
|
62
93
|
};
|
|
63
94
|
export default _default;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
+
QUESTION_TOOL2,
|
|
2
3
|
answerInput2,
|
|
3
|
-
questionOutput2,
|
|
4
4
|
questionParameters2,
|
|
5
5
|
question2
|
|
6
|
-
} from "../../chunks/bash-description-
|
|
6
|
+
} from "../../chunks/bash-description-s6v2m3ch.js";
|
|
7
7
|
|
|
8
8
|
// src/question/question.ts
|
|
9
9
|
import { definePart, dev } from "@nyte-ai/core";
|
|
10
|
-
import { SdkError } from "@nyte-ai/schema";
|
|
10
|
+
import { asId, SdkError } from "@nyte-ai/schema";
|
|
11
|
+
var WAIT_MS = 60000;
|
|
11
12
|
function normalizeAnswers(items, supplied) {
|
|
12
13
|
if (supplied.length !== items.length)
|
|
13
14
|
throw new SdkError("invalid", "Submit one answer list for each question.");
|
|
@@ -22,18 +23,58 @@ function normalizeAnswers(items, supplied) {
|
|
|
22
23
|
return item.multiple ? selected.toSorted() : selected;
|
|
23
24
|
});
|
|
24
25
|
}
|
|
26
|
+
function formatAnswers(items, answers, form) {
|
|
27
|
+
return items.map((item, index) => `${form === "prompt" ? item.question : item.header}: ${answers[index].join(", ") || "Unanswered"}`).join(form === "prompt" ? `
|
|
28
|
+
` : " · ");
|
|
29
|
+
}
|
|
25
30
|
var handlers = {
|
|
26
31
|
async answer(input, context) {
|
|
27
|
-
let
|
|
32
|
+
let answered;
|
|
28
33
|
const outcome = await context.part.update((current) => {
|
|
29
34
|
const normalized = normalizeAnswers(current.questions, input.answers);
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const phase = current.phase;
|
|
36
|
+
if (phase.kind === "skipped")
|
|
37
|
+
throw new SdkError("invalid", "These questions were skipped.");
|
|
38
|
+
if (phase.kind === "answered") {
|
|
39
|
+
if (JSON.stringify(phase.answers) !== JSON.stringify(normalized))
|
|
40
|
+
throw new SdkError("invalid", "These questions were already answered.");
|
|
41
|
+
answered = { asked: current.questions, phase };
|
|
42
|
+
return current;
|
|
43
|
+
}
|
|
44
|
+
const next = {
|
|
45
|
+
kind: "answered",
|
|
46
|
+
answers: normalized,
|
|
47
|
+
head: phase.kind === "open" ? phase.head : null
|
|
48
|
+
};
|
|
49
|
+
answered = { asked: current.questions, phase: next };
|
|
50
|
+
return { ...current, phase: next };
|
|
32
51
|
});
|
|
33
52
|
if (outcome.kind !== "updated")
|
|
34
53
|
throw new Error(`The questions could not be answered: ${outcome.kind}.`);
|
|
35
|
-
if (
|
|
36
|
-
|
|
54
|
+
if (answered?.phase.kind !== "answered" || answered.phase.head === null)
|
|
55
|
+
return;
|
|
56
|
+
await context.api.sdk.session(context.session).head(answered.phase.head).send(`The user answered your earlier question:
|
|
57
|
+
${formatAnswers(answered.asked, answered.phase.answers, "prompt")}`, {
|
|
58
|
+
delivery: "attach",
|
|
59
|
+
source: {
|
|
60
|
+
kind: "answer",
|
|
61
|
+
part: context.part.id,
|
|
62
|
+
label: formatAnswers(answered.asked, answered.phase.answers, "label")
|
|
63
|
+
},
|
|
64
|
+
id: asId(`question:${context.part.id}`)
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
async skip(_, context) {
|
|
68
|
+
const outcome = await context.part.update((current) => {
|
|
69
|
+
const phase = current.phase;
|
|
70
|
+
if (phase.kind === "answered")
|
|
71
|
+
throw new SdkError("invalid", "These questions were already answered.");
|
|
72
|
+
if (phase.kind === "skipped")
|
|
73
|
+
return current;
|
|
74
|
+
return { ...current, phase: { kind: "skipped", late: phase.kind === "open" } };
|
|
75
|
+
});
|
|
76
|
+
if (outcome.kind !== "updated")
|
|
77
|
+
throw new Error(`The questions could not be skipped: ${outcome.kind}.`);
|
|
37
78
|
}
|
|
38
79
|
};
|
|
39
80
|
var question = definePart({
|
|
@@ -41,10 +82,9 @@ var question = definePart({
|
|
|
41
82
|
onAction: (action, input, context) => handlers[action](input, context)
|
|
42
83
|
});
|
|
43
84
|
var ask = {
|
|
44
|
-
name:
|
|
45
|
-
description: "Ask the user one or more questions and wait for their answers. Give each option a short label and a description. Use multiple when several choices may apply. The user can also write their own answer.",
|
|
85
|
+
name: QUESTION_TOOL2,
|
|
86
|
+
description: "Ask the user one or more questions and wait up to a minute for their answers. Give each option a short label and a description. Use multiple when several choices may apply. The user can also write their own answer. If they don't answer in time, keep working; their answer arrives later as a message.",
|
|
46
87
|
parameters: questionParameters2,
|
|
47
|
-
output: questionOutput2,
|
|
48
88
|
class: (args) => ({
|
|
49
89
|
kind: "custom",
|
|
50
90
|
label: args.questions.map((item) => item.header).join(", ")
|
|
@@ -58,26 +98,38 @@ var ask = {
|
|
|
58
98
|
throw new SdkError("invalid", "Question option labels must be distinct.");
|
|
59
99
|
}
|
|
60
100
|
const part = await invocation.session.parts.create(question, {
|
|
61
|
-
state: {
|
|
101
|
+
state: { call: invocation.call, questions: args.questions, phase: { kind: "asking" } },
|
|
62
102
|
placement: { kind: "modal" }
|
|
63
103
|
});
|
|
64
104
|
dev("question", "asked", { call: invocation.call, part: part.id });
|
|
65
|
-
const outcome = await invocation.wait({
|
|
105
|
+
const outcome = await invocation.wait({
|
|
106
|
+
kind: "part",
|
|
107
|
+
part: part.id,
|
|
108
|
+
deadline: invocation.now() + WAIT_MS
|
|
109
|
+
});
|
|
66
110
|
const checked = outcome.kind === "part" && outcome.answer?.action === "answer" ? await answerInput2["~standard"].validate(outcome.answer.input) : undefined;
|
|
67
|
-
const
|
|
111
|
+
const deadline = outcome.kind === "deadline" ? await stopWaiting(part, invocation.head) : null;
|
|
112
|
+
const reply = deadline?.kind === "answered" && deadline.head === null ? deadline.answers : checked !== undefined && checked.issues === undefined ? normalizeAnswers(args.questions, checked.value.answers) : null;
|
|
113
|
+
const unanswered = deadline?.kind === "open" ? "No answer yet. The question stays open, and the user's answer will arrive as a message." : "The user did not answer.";
|
|
68
114
|
return {
|
|
69
115
|
content: [
|
|
70
116
|
{
|
|
71
117
|
kind: "text",
|
|
72
|
-
text: reply === null ?
|
|
73
|
-
`)
|
|
118
|
+
text: reply === null ? `${unanswered} Continue with your best judgment and say what you assumed.` : formatAnswers(args.questions, reply, "prompt")
|
|
74
119
|
}
|
|
75
120
|
],
|
|
76
|
-
output: { answers: reply },
|
|
77
121
|
parts: [part.id]
|
|
78
122
|
};
|
|
79
123
|
}
|
|
80
124
|
};
|
|
125
|
+
async function stopWaiting(part, head) {
|
|
126
|
+
let phase = { kind: "open", head };
|
|
127
|
+
await part.update((current) => {
|
|
128
|
+
phase = current.phase.kind === "asking" ? { kind: "open", head } : current.phase;
|
|
129
|
+
return { ...current, phase };
|
|
130
|
+
});
|
|
131
|
+
return phase;
|
|
132
|
+
}
|
|
81
133
|
var question_default = {
|
|
82
134
|
id: "question",
|
|
83
135
|
contribute: { parts: [question], tools: [ask] }
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { Infer, PartId, SessionView } from "@nyte-ai/schema";
|
|
1
|
+
import type { CallId, Infer, PartId, PartView, SessionView } from "@nyte-ai/schema";
|
|
2
|
+
/** The question tool's name, which clients match to draw its calls. */
|
|
3
|
+
export declare const QUESTION_TOOL = "question";
|
|
2
4
|
declare const info: import("@nyte-ai/schema").Schema<{
|
|
3
5
|
question: string;
|
|
4
6
|
header: string;
|
|
@@ -11,10 +13,8 @@ declare const info: import("@nyte-ai/schema").Schema<{
|
|
|
11
13
|
export declare const answerInput: import("@nyte-ai/schema").Schema<{
|
|
12
14
|
answers: string[][];
|
|
13
15
|
}>;
|
|
14
|
-
export declare const questionOutput: import("@nyte-ai/schema").Schema<{
|
|
15
|
-
answers: string[][] | null;
|
|
16
|
-
}>;
|
|
17
16
|
declare const state: import("@nyte-ai/schema").Schema<{
|
|
17
|
+
call: import("@nyte-ai/schema").Id<"call">;
|
|
18
18
|
questions: {
|
|
19
19
|
question: string;
|
|
20
20
|
header: string;
|
|
@@ -24,7 +24,19 @@ declare const state: import("@nyte-ai/schema").Schema<{
|
|
|
24
24
|
}[];
|
|
25
25
|
multiple?: boolean | undefined;
|
|
26
26
|
}[];
|
|
27
|
-
|
|
27
|
+
phase: {
|
|
28
|
+
kind: "asking";
|
|
29
|
+
} | {
|
|
30
|
+
kind: "open";
|
|
31
|
+
head: import("@nyte-ai/schema").Id<"head">;
|
|
32
|
+
} | {
|
|
33
|
+
kind: "answered";
|
|
34
|
+
answers: string[][];
|
|
35
|
+
head: import("@nyte-ai/schema").Id<"head"> | null;
|
|
36
|
+
} | {
|
|
37
|
+
kind: "skipped";
|
|
38
|
+
late: boolean;
|
|
39
|
+
};
|
|
28
40
|
}>;
|
|
29
41
|
export declare const questionParameters: import("@nyte-ai/schema").Schema<{
|
|
30
42
|
questions: {
|
|
@@ -41,11 +53,18 @@ export declare const questionParameters: import("@nyte-ai/schema").Schema<{
|
|
|
41
53
|
export type QuestionInfo = Infer<typeof info>;
|
|
42
54
|
/** One answer list per question, in request order. An empty list leaves a question unanswered. */
|
|
43
55
|
export type QuestionAnswers = Infer<typeof answerInput>["answers"];
|
|
44
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* A grouped question request: the call that asked it, its questions, and where it stands.
|
|
58
|
+
* `asking` while the call waits; `open` once the call stopped waiting and an answer goes to `head`
|
|
59
|
+
* as a message. `answered` keeps that `head`, or null when the waiting call took the answer;
|
|
60
|
+
* `skipped` says whether the user declined after the call stopped waiting.
|
|
61
|
+
* A run that ends first shows on the part's status, not here.
|
|
62
|
+
*/
|
|
45
63
|
export type QuestionState = Infer<typeof state>;
|
|
64
|
+
export type QuestionPhase = QuestionState["phase"];
|
|
46
65
|
/**
|
|
47
|
-
* A grouped modal request.
|
|
48
|
-
*
|
|
66
|
+
* A grouped modal request. `answer` submits all questions at once and `skip` declines them; the
|
|
67
|
+
* first of either holds across retries and restarts.
|
|
49
68
|
*
|
|
50
69
|
* @category plugins
|
|
51
70
|
* @since 0.1.0
|
|
@@ -53,6 +72,7 @@ export type QuestionState = Infer<typeof state>;
|
|
|
53
72
|
export declare const question: {
|
|
54
73
|
kind: string;
|
|
55
74
|
state: import("@nyte-ai/schema").Schema<{
|
|
75
|
+
call: import("@nyte-ai/schema").Id<"call">;
|
|
56
76
|
questions: {
|
|
57
77
|
question: string;
|
|
58
78
|
header: string;
|
|
@@ -62,7 +82,19 @@ export declare const question: {
|
|
|
62
82
|
}[];
|
|
63
83
|
multiple?: boolean | undefined;
|
|
64
84
|
}[];
|
|
65
|
-
|
|
85
|
+
phase: {
|
|
86
|
+
kind: "asking";
|
|
87
|
+
} | {
|
|
88
|
+
kind: "open";
|
|
89
|
+
head: import("@nyte-ai/schema").Id<"head">;
|
|
90
|
+
} | {
|
|
91
|
+
kind: "answered";
|
|
92
|
+
answers: string[][];
|
|
93
|
+
head: import("@nyte-ai/schema").Id<"head"> | null;
|
|
94
|
+
} | {
|
|
95
|
+
kind: "skipped";
|
|
96
|
+
late: boolean;
|
|
97
|
+
};
|
|
66
98
|
}>;
|
|
67
99
|
actions: {
|
|
68
100
|
answer: {
|
|
@@ -70,8 +102,12 @@ export declare const question: {
|
|
|
70
102
|
answers: string[][];
|
|
71
103
|
}>;
|
|
72
104
|
};
|
|
105
|
+
skip: {
|
|
106
|
+
input: import("@nyte-ai/schema").Schema<object>;
|
|
107
|
+
};
|
|
73
108
|
};
|
|
74
109
|
fallback: (current: {
|
|
110
|
+
call: import("@nyte-ai/schema").Id<"call">;
|
|
75
111
|
questions: {
|
|
76
112
|
question: string;
|
|
77
113
|
header: string;
|
|
@@ -81,14 +117,27 @@ export declare const question: {
|
|
|
81
117
|
}[];
|
|
82
118
|
multiple?: boolean | undefined;
|
|
83
119
|
}[];
|
|
84
|
-
|
|
120
|
+
phase: {
|
|
121
|
+
kind: "asking";
|
|
122
|
+
} | {
|
|
123
|
+
kind: "open";
|
|
124
|
+
head: import("@nyte-ai/schema").Id<"head">;
|
|
125
|
+
} | {
|
|
126
|
+
kind: "answered";
|
|
127
|
+
answers: string[][];
|
|
128
|
+
head: import("@nyte-ai/schema").Id<"head"> | null;
|
|
129
|
+
} | {
|
|
130
|
+
kind: "skipped";
|
|
131
|
+
late: boolean;
|
|
132
|
+
};
|
|
85
133
|
}, { id }: {
|
|
86
134
|
readonly id: PartId;
|
|
87
135
|
}) => string;
|
|
88
136
|
};
|
|
89
|
-
/** A grouped request still waiting for the user, with the part its submission goes to. */
|
|
137
|
+
/** A grouped request still waiting for the user, with the part its submission goes to. `late` once the asking call stopped waiting and the agent carried on. */
|
|
90
138
|
export type OpenQuestion = Pick<QuestionState, "questions"> & {
|
|
91
139
|
readonly part: PartId;
|
|
140
|
+
readonly late: boolean;
|
|
92
141
|
};
|
|
93
142
|
/**
|
|
94
143
|
* Returns unanswered live question requests, oldest first. Requests from a
|
|
@@ -98,4 +147,17 @@ export type OpenQuestion = Pick<QuestionState, "questions"> & {
|
|
|
98
147
|
* @since 0.1.0
|
|
99
148
|
*/
|
|
100
149
|
export declare function openQuestions(view: Pick<SessionView, "parts"> | undefined): readonly OpenQuestion[];
|
|
150
|
+
/**
|
|
151
|
+
* The question part a call made, found by its `call` with one string comparison per part; the
|
|
152
|
+
* caller validates only the match with {@link readQuestion}.
|
|
153
|
+
*
|
|
154
|
+
* @category plugins
|
|
155
|
+
*/
|
|
156
|
+
export declare function findQuestionPart(parts: readonly PartView[], call: CallId): PartView | undefined;
|
|
157
|
+
/**
|
|
158
|
+
* A question part's state, or null when it doesn't parse.
|
|
159
|
+
*
|
|
160
|
+
* @category plugins
|
|
161
|
+
*/
|
|
162
|
+
export declare function readQuestion(part: PartView): QuestionState | null;
|
|
101
163
|
export {};
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
+
QUESTION_TOOL2,
|
|
2
3
|
answerInput2,
|
|
3
|
-
questionOutput2,
|
|
4
4
|
questionParameters2,
|
|
5
5
|
question2,
|
|
6
|
-
openQuestions2
|
|
7
|
-
|
|
6
|
+
openQuestions2,
|
|
7
|
+
findQuestionPart2,
|
|
8
|
+
readQuestion2
|
|
9
|
+
} from "../../chunks/bash-description-s6v2m3ch.js";
|
|
8
10
|
export {
|
|
11
|
+
QUESTION_TOOL2 as QUESTION_TOOL,
|
|
9
12
|
answerInput2 as answerInput,
|
|
13
|
+
findQuestionPart2 as findQuestionPart,
|
|
10
14
|
openQuestions2 as openQuestions,
|
|
11
15
|
question2 as question,
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
questionParameters2 as questionParameters,
|
|
17
|
+
readQuestion2 as readQuestion
|
|
14
18
|
};
|
package/dist/src/rename.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ declare const _default: {
|
|
|
20
20
|
readonly message: import("@nyte-ai/schema").Id<"message">;
|
|
21
21
|
} | {
|
|
22
22
|
readonly kind: "continuation";
|
|
23
|
-
readonly from: "child" | "job" | "wake";
|
|
23
|
+
readonly from: "answer" | "child" | "job" | "wake";
|
|
24
24
|
};
|
|
25
25
|
}>, { api }: {
|
|
26
26
|
readonly api: {
|