@dudousxd/nestjs-agent-react 0.11.0 → 0.12.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 +22 -2
- package/dist/index.cjs +105 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -2
- package/dist/index.d.ts +47 -2
- package/dist/index.js +99 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -186,12 +186,32 @@ const transcript = useChatTranscript({
|
|
|
186
186
|
});
|
|
187
187
|
|
|
188
188
|
// block.kind === 'elicitation' →
|
|
189
|
-
// { toolCallId, preamble, questionCount, isPending, outcome, error,
|
|
190
|
-
// questions: [{ id, prompt, position, multiple, selected,
|
|
189
|
+
// { toolCallId, preamble, questionCount, isPending, isValid, outcome, error,
|
|
190
|
+
// questions: [{ id, prompt, description, input, position, multiple, selected, value, error,
|
|
191
|
+
// isPristine, setValue(raw),
|
|
191
192
|
// options: [{ value, label, hotkey, isSelected, isDefault, select() }] }],
|
|
192
193
|
// answer: { available, isSubmitting, run() }, skip: { … } }
|
|
193
194
|
```
|
|
194
195
|
|
|
196
|
+
**Typed questions.** A question with `input` asks for a value instead of a pick — `input.type` is
|
|
197
|
+
`text` · `textarea` · `number` · `boolean` · `date` · `email` · `url` · `select` (a pick from
|
|
198
|
+
`options` again), with optional `placeholder`, `required`, `min`, `max` and `pattern`. `options` may
|
|
199
|
+
be empty for one. Render the control from `input.type` and hand whatever it produces to
|
|
200
|
+
`question.setValue(raw)`: it is coerced with `coerceAnswer` to the canonical strings the wire
|
|
201
|
+
carries (numbers as decimals, booleans as `"true"`/`"false"`, dates as `YYYY-MM-DD`). `question.error`
|
|
202
|
+
is the server's own verdict on the current selection (`validateAnswer`), and `block.isValid` is all
|
|
203
|
+
of them — the answer route answers `400` with the same message for anything it would refuse.
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
{q.input?.type === 'number' ? (
|
|
207
|
+
<input type="number" value={q.value} placeholder={q.input.placeholder}
|
|
208
|
+
min={q.input.min} max={q.input.max} onChange={(e) => q.setValue(e.target.value)} />
|
|
209
|
+
) : q.input?.type === 'boolean' ? (
|
|
210
|
+
<input type="checkbox" checked={q.value === 'true'} onChange={(e) => q.setValue(e.target.checked)} />
|
|
211
|
+
) : null}
|
|
212
|
+
{q.error && !q.isPristine ? <small role="alert">{q.error}</small> : null}
|
|
213
|
+
```
|
|
214
|
+
|
|
195
215
|
Every option the agent pre-picked comes back as `isDefault` and starts `isSelected`, so confirming
|
|
196
216
|
is enough. `answer.run()` submits **only the questions the user touched** — the rest are omitted on
|
|
197
217
|
purpose, so the server applies the same defaults it showed and the settled row still records which
|
package/dist/index.cjs
CHANGED
|
@@ -44,6 +44,7 @@ __export(src_exports, {
|
|
|
44
44
|
approvalCountdown: () => approvalCountdown,
|
|
45
45
|
backgroundRunsFromThread: () => backgroundRunsFromThread,
|
|
46
46
|
buildTranscriptBlocks: () => buildTranscriptBlocks,
|
|
47
|
+
coerceAnswer: () => coerceAnswer,
|
|
47
48
|
correctedCallIds: () => correctedCallIds,
|
|
48
49
|
createSkillsSource: () => createSkillsSource,
|
|
49
50
|
describeTimestamp: () => describeTimestamp,
|
|
@@ -76,7 +77,9 @@ __export(src_exports, {
|
|
|
76
77
|
useSpeechRecognition: () => useSpeechRecognition,
|
|
77
78
|
useStickToBottom: () => useStickToBottom,
|
|
78
79
|
useToolCatalog: () => useToolCatalog,
|
|
79
|
-
useTranscriptItem: () => useTranscriptItem
|
|
80
|
+
useTranscriptItem: () => useTranscriptItem,
|
|
81
|
+
validateAnswer: () => import_nestjs_agent_core.validateElicitationAnswer,
|
|
82
|
+
validateAnswerValue: () => import_nestjs_agent_core.validateElicitationValue
|
|
80
83
|
});
|
|
81
84
|
module.exports = __toCommonJS(src_exports);
|
|
82
85
|
|
|
@@ -1057,8 +1060,66 @@ var import_react6 = __toESM(require("react"), 1);
|
|
|
1057
1060
|
var import_react5 = require("react");
|
|
1058
1061
|
|
|
1059
1062
|
// src/transcript/model.ts
|
|
1063
|
+
var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
|
|
1060
1064
|
var import_ai2 = require("ai");
|
|
1061
1065
|
|
|
1066
|
+
// src/elicitation/answers.ts
|
|
1067
|
+
var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
|
|
1068
|
+
function pad(value) {
|
|
1069
|
+
return String(value).padStart(2, "0");
|
|
1070
|
+
}
|
|
1071
|
+
__name(pad, "pad");
|
|
1072
|
+
function toDay(date) {
|
|
1073
|
+
if (Number.isNaN(date.getTime())) {
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
1077
|
+
}
|
|
1078
|
+
__name(toDay, "toDay");
|
|
1079
|
+
function coerceOne(type, raw) {
|
|
1080
|
+
if (raw === null || raw === void 0) {
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
if (Array.isArray(raw)) {
|
|
1084
|
+
return null;
|
|
1085
|
+
}
|
|
1086
|
+
if (raw instanceof Date) {
|
|
1087
|
+
return type === "date" || type === void 0 ? toDay(raw) : raw.toISOString();
|
|
1088
|
+
}
|
|
1089
|
+
if (typeof raw === "boolean") {
|
|
1090
|
+
return raw ? "true" : "false";
|
|
1091
|
+
}
|
|
1092
|
+
if (typeof raw === "number") {
|
|
1093
|
+
return Number.isFinite(raw) ? String(raw) : null;
|
|
1094
|
+
}
|
|
1095
|
+
const text = raw;
|
|
1096
|
+
switch (type) {
|
|
1097
|
+
case "number":
|
|
1098
|
+
case "email":
|
|
1099
|
+
case "url":
|
|
1100
|
+
case "date":
|
|
1101
|
+
return text.trim() === "" ? null : text.trim();
|
|
1102
|
+
case "boolean": {
|
|
1103
|
+
const lowered = text.trim().toLowerCase();
|
|
1104
|
+
if (lowered === "true" || lowered === "on" || lowered === "yes") return "true";
|
|
1105
|
+
if (lowered === "false" || lowered === "off" || lowered === "no") return "false";
|
|
1106
|
+
return lowered === "" ? null : text;
|
|
1107
|
+
}
|
|
1108
|
+
default:
|
|
1109
|
+
return text === "" ? null : text;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
__name(coerceOne, "coerceOne");
|
|
1113
|
+
function coerceAnswer(question, raw) {
|
|
1114
|
+
const type = question.input?.type;
|
|
1115
|
+
const items = Array.isArray(raw) ? raw : [
|
|
1116
|
+
raw
|
|
1117
|
+
];
|
|
1118
|
+
const values = items.map((item) => coerceOne(type, item)).filter((value) => value !== null);
|
|
1119
|
+
return question.multiple === true ? values : values.slice(0, 1);
|
|
1120
|
+
}
|
|
1121
|
+
__name(coerceAnswer, "coerceAnswer");
|
|
1122
|
+
|
|
1062
1123
|
// src/presentation/tool-activity.ts
|
|
1063
1124
|
var import_ai = require("ai");
|
|
1064
1125
|
|
|
@@ -1595,11 +1656,16 @@ function readElicitationRequest(part) {
|
|
|
1595
1656
|
}
|
|
1596
1657
|
const questions = [];
|
|
1597
1658
|
for (const candidate of input.questions) {
|
|
1598
|
-
if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string"
|
|
1659
|
+
if (!isRecord2(candidate) || typeof candidate.id !== "string" || typeof candidate.prompt !== "string") {
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
const input2 = (0, import_nestjs_agent_core2.readElicitationInput)(candidate.input) ?? null;
|
|
1663
|
+
const rawOptions = Array.isArray(candidate.options) ? candidate.options : [];
|
|
1664
|
+
if (rawOptions.length === 0 && (input2 === null || input2.type === "select")) {
|
|
1599
1665
|
return null;
|
|
1600
1666
|
}
|
|
1601
1667
|
const options = [];
|
|
1602
|
-
for (const option of
|
|
1668
|
+
for (const option of rawOptions) {
|
|
1603
1669
|
if (!isRecord2(option) || typeof option.value !== "string" || typeof option.label !== "string") {
|
|
1604
1670
|
return null;
|
|
1605
1671
|
}
|
|
@@ -1612,7 +1678,10 @@ function readElicitationRequest(part) {
|
|
|
1612
1678
|
questions.push({
|
|
1613
1679
|
id: candidate.id,
|
|
1614
1680
|
prompt: candidate.prompt,
|
|
1681
|
+
description: typeof candidate.description === "string" ? candidate.description : null,
|
|
1682
|
+
input: input2,
|
|
1615
1683
|
multiple: candidate.multiple === true,
|
|
1684
|
+
allowFreeText: candidate.allowFreeText === true,
|
|
1616
1685
|
defaults: Array.isArray(candidate.defaults) ? candidate.defaults.filter((value) => typeof value === "string") : [],
|
|
1617
1686
|
options
|
|
1618
1687
|
});
|
|
@@ -1648,12 +1717,38 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
1648
1717
|
const picked = isPending ? options.picked(toolCallId, question.id) : void 0;
|
|
1649
1718
|
const selected = picked ?? outcome?.answers[question.id] ?? question.defaults;
|
|
1650
1719
|
const pick = /* @__PURE__ */ __name((values) => options.pick(toolCallId, question.id, values), "pick");
|
|
1720
|
+
const error = isPending ? (0, import_nestjs_agent_core2.validateElicitationAnswer)({
|
|
1721
|
+
id: question.id,
|
|
1722
|
+
prompt: question.prompt,
|
|
1723
|
+
options: question.options.map(({ value, label }) => ({
|
|
1724
|
+
value,
|
|
1725
|
+
label
|
|
1726
|
+
})),
|
|
1727
|
+
...question.input !== null ? {
|
|
1728
|
+
input: question.input
|
|
1729
|
+
} : {},
|
|
1730
|
+
...question.multiple ? {
|
|
1731
|
+
multiple: true
|
|
1732
|
+
} : {},
|
|
1733
|
+
...question.allowFreeText ? {
|
|
1734
|
+
allowFreeText: true
|
|
1735
|
+
} : {}
|
|
1736
|
+
}, selected) : null;
|
|
1651
1737
|
return {
|
|
1652
1738
|
id: question.id,
|
|
1653
1739
|
prompt: question.prompt,
|
|
1740
|
+
description: question.description,
|
|
1741
|
+
input: question.input,
|
|
1654
1742
|
multiple: question.multiple,
|
|
1655
1743
|
position: index + 1,
|
|
1656
1744
|
selected,
|
|
1745
|
+
value: selected[0] ?? "",
|
|
1746
|
+
error,
|
|
1747
|
+
setValue: /* @__PURE__ */ __name((raw) => {
|
|
1748
|
+
if (isPending) {
|
|
1749
|
+
pick(coerceAnswer(question, raw));
|
|
1750
|
+
}
|
|
1751
|
+
}, "setValue"),
|
|
1657
1752
|
isPristine: isPending ? picked === void 0 : outcome?.defaulted.includes(question.id) ?? true,
|
|
1658
1753
|
options: question.options.map((option) => ({
|
|
1659
1754
|
value: option.value,
|
|
@@ -1688,6 +1783,7 @@ function buildElicitationBlock(key, part, request, options) {
|
|
|
1688
1783
|
questions,
|
|
1689
1784
|
questionCount: questions.length,
|
|
1690
1785
|
isPending,
|
|
1786
|
+
isValid: questions.every((question) => question.error === null),
|
|
1691
1787
|
outcome,
|
|
1692
1788
|
error: options.errorOf(toolCallId),
|
|
1693
1789
|
answer: {
|
|
@@ -3196,7 +3292,7 @@ function useApprovalCountdown(expiresAt, options = {}) {
|
|
|
3196
3292
|
__name(useApprovalCountdown, "useApprovalCountdown");
|
|
3197
3293
|
|
|
3198
3294
|
// src/stored-message-to-ui-message.ts
|
|
3199
|
-
var
|
|
3295
|
+
var import_nestjs_agent_core3 = require("@dudousxd/nestjs-agent-core");
|
|
3200
3296
|
function isRefusal(result) {
|
|
3201
3297
|
if (result.denied === true) {
|
|
3202
3298
|
return true;
|
|
@@ -3209,7 +3305,7 @@ function refusalReason(result) {
|
|
|
3209
3305
|
const { output } = result;
|
|
3210
3306
|
if (output !== null && typeof output === "object" && "reason" in output) {
|
|
3211
3307
|
const reason = output.reason;
|
|
3212
|
-
return typeof reason === "string" && reason !==
|
|
3308
|
+
return typeof reason === "string" && reason !== import_nestjs_agent_core3.DEFAULT_REFUSAL_REASON ? reason : void 0;
|
|
3213
3309
|
}
|
|
3214
3310
|
return void 0;
|
|
3215
3311
|
}
|
|
@@ -3757,6 +3853,7 @@ __name(mergeHeaders, "mergeHeaders");
|
|
|
3757
3853
|
approvalCountdown,
|
|
3758
3854
|
backgroundRunsFromThread,
|
|
3759
3855
|
buildTranscriptBlocks,
|
|
3856
|
+
coerceAnswer,
|
|
3760
3857
|
correctedCallIds,
|
|
3761
3858
|
createSkillsSource,
|
|
3762
3859
|
describeTimestamp,
|
|
@@ -3789,6 +3886,8 @@ __name(mergeHeaders, "mergeHeaders");
|
|
|
3789
3886
|
useSpeechRecognition,
|
|
3790
3887
|
useStickToBottom,
|
|
3791
3888
|
useToolCatalog,
|
|
3792
|
-
useTranscriptItem
|
|
3889
|
+
useTranscriptItem,
|
|
3890
|
+
validateAnswer,
|
|
3891
|
+
validateAnswerValue
|
|
3793
3892
|
});
|
|
3794
3893
|
//# sourceMappingURL=index.cjs.map
|