@cognipeer/agent-sdk 0.6.5 → 0.6.6
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 +7 -2
- package/dist/index.cjs +306 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -2
- package/dist/index.d.ts +110 -2
- package/dist/index.mjs +305 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -743,6 +743,7 @@ function createResolverNode() {
|
|
|
743
743
|
toolHistory: state.toolHistory || [],
|
|
744
744
|
toolHistoryArchived: state.toolHistoryArchived || [],
|
|
745
745
|
pendingApprovals: state.pendingApprovals || [],
|
|
746
|
+
pendingUserQuestions: state.pendingUserQuestions || [],
|
|
746
747
|
plan: state.plan || null,
|
|
747
748
|
planVersion: state.planVersion || 0
|
|
748
749
|
};
|
|
@@ -2584,13 +2585,16 @@ function createToolsNode(initialTools, opts) {
|
|
|
2584
2585
|
const traceSession = state.ctx?.__traceSession;
|
|
2585
2586
|
const pendingApprovals = Array.isArray(state.pendingApprovals) ? state.pendingApprovals.map((entry) => ({ ...entry })) : [];
|
|
2586
2587
|
const pendingByCallId = new Map(pendingApprovals.map((entry) => [entry.toolCallId, entry]));
|
|
2588
|
+
const pendingUserQuestions = Array.isArray(state.pendingUserQuestions) ? state.pendingUserQuestions.map((entry) => ({ ...entry })) : [];
|
|
2587
2589
|
let awaitingApproval = false;
|
|
2590
|
+
let awaitingUserQuestion = false;
|
|
2588
2591
|
for (const tool of toolByName.values()) {
|
|
2589
2592
|
const anyTool = tool;
|
|
2590
2593
|
if (anyTool._stateRef && typeof anyTool._stateRef === "object") {
|
|
2591
2594
|
anyTool._stateRef.toolHistory = state.toolHistory;
|
|
2592
2595
|
anyTool._stateRef.toolHistoryArchived = state.toolHistoryArchived;
|
|
2593
2596
|
anyTool._stateRef.pendingApprovals = pendingApprovals;
|
|
2597
|
+
anyTool._stateRef.pendingUserQuestions = pendingUserQuestions;
|
|
2594
2598
|
anyTool._stateRef.messages = state.messages;
|
|
2595
2599
|
anyTool._stateRef.ctx = state.ctx || (state.ctx = {});
|
|
2596
2600
|
anyTool._stateRef.__onEvent = onEvent;
|
|
@@ -2664,6 +2668,7 @@ function createToolsNode(initialTools, opts) {
|
|
|
2664
2668
|
const toolStateRef = tool._stateRef && typeof tool._stateRef === "object" ? tool._stateRef : null;
|
|
2665
2669
|
if (toolStateRef) {
|
|
2666
2670
|
toolStateRef.pendingApprovals = pendingApprovals;
|
|
2671
|
+
toolStateRef.pendingUserQuestions = pendingUserQuestions;
|
|
2667
2672
|
toolStateRef.ctx = state.ctx || (state.ctx = {});
|
|
2668
2673
|
toolStateRef.__currentToolCallId = toolCallId;
|
|
2669
2674
|
delete toolStateRef.__awaitingApproval;
|
|
@@ -2875,6 +2880,22 @@ function createToolsNode(initialTools, opts) {
|
|
|
2875
2880
|
approval: pendingApproval
|
|
2876
2881
|
};
|
|
2877
2882
|
}
|
|
2883
|
+
if (output && typeof output === "object" && output.__awaitingUserQuestion) {
|
|
2884
|
+
if (toolStateRef?.ctx && typeof toolStateRef.ctx === "object") {
|
|
2885
|
+
state.ctx = toolStateRef.ctx;
|
|
2886
|
+
}
|
|
2887
|
+
const pendingQuestion = pendingUserQuestions.find(
|
|
2888
|
+
(entry) => entry.toolCallId === output.toolCallId || entry.id === output.id
|
|
2889
|
+
);
|
|
2890
|
+
if (!pendingQuestion) {
|
|
2891
|
+
throw new Error(`Tool ${toolName} requested a user question but no pending question entry was recorded.`);
|
|
2892
|
+
}
|
|
2893
|
+
awaitingUserQuestion = true;
|
|
2894
|
+
return {
|
|
2895
|
+
status: "awaiting_user_question",
|
|
2896
|
+
userQuestion: pendingQuestion
|
|
2897
|
+
};
|
|
2898
|
+
}
|
|
2878
2899
|
if (output && typeof output === "object" && output.__finalStructuredOutput) {
|
|
2879
2900
|
if (!state.ctx) state.ctx = {};
|
|
2880
2901
|
state.ctx.__structuredOutputParsed = output.data;
|
|
@@ -3012,15 +3033,19 @@ function createToolsNode(initialTools, opts) {
|
|
|
3012
3033
|
return false;
|
|
3013
3034
|
};
|
|
3014
3035
|
for (const idx of approvalIndices) {
|
|
3015
|
-
if (awaitingApproval || shouldStop) break;
|
|
3036
|
+
if (awaitingApproval || awaitingUserQuestion || shouldStop) break;
|
|
3016
3037
|
if (checkCancellationStop()) break;
|
|
3017
3038
|
const result = await runOne(planned[idx], orderedSlots[idx]);
|
|
3018
3039
|
if (result.status === "awaiting_approval") {
|
|
3019
3040
|
awaitingApproval = true;
|
|
3020
3041
|
break;
|
|
3021
3042
|
}
|
|
3043
|
+
if (result.status === "awaiting_user_question") {
|
|
3044
|
+
awaitingUserQuestion = true;
|
|
3045
|
+
break;
|
|
3046
|
+
}
|
|
3022
3047
|
}
|
|
3023
|
-
if (!awaitingApproval && !shouldStop && parallelIndices.length > 0) {
|
|
3048
|
+
if (!awaitingApproval && !awaitingUserQuestion && !shouldStop && parallelIndices.length > 0) {
|
|
3024
3049
|
const concurrency = Math.max(1, Math.min(limits.maxParallelTools, parallelIndices.length));
|
|
3025
3050
|
let cursor = 0;
|
|
3026
3051
|
const workerError = {};
|
|
@@ -3028,7 +3053,7 @@ function createToolsNode(initialTools, opts) {
|
|
|
3028
3053
|
for (let w = 0; w < concurrency; w++) {
|
|
3029
3054
|
workers.push((async () => {
|
|
3030
3055
|
while (true) {
|
|
3031
|
-
if (workerError.err || shouldStop || awaitingApproval) return;
|
|
3056
|
+
if (workerError.err || shouldStop || awaitingApproval || awaitingUserQuestion) return;
|
|
3032
3057
|
const i = cursor++;
|
|
3033
3058
|
if (i >= parallelIndices.length) return;
|
|
3034
3059
|
if (checkCancellationStop()) return;
|
|
@@ -3039,6 +3064,10 @@ function createToolsNode(initialTools, opts) {
|
|
|
3039
3064
|
awaitingApproval = true;
|
|
3040
3065
|
return;
|
|
3041
3066
|
}
|
|
3067
|
+
if (result.status === "awaiting_user_question") {
|
|
3068
|
+
awaitingUserQuestion = true;
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3042
3071
|
} catch (err) {
|
|
3043
3072
|
workerError.err = err;
|
|
3044
3073
|
return;
|
|
@@ -3101,11 +3130,12 @@ function createToolsNode(initialTools, opts) {
|
|
|
3101
3130
|
toolCache: state.toolCache,
|
|
3102
3131
|
// Explicitly propagate ctx so callers using `{ ...state, ...delta }`
|
|
3103
3132
|
// do not silently capture a stale ctx reference. Mutations to
|
|
3104
|
-
// __summarizationExhausted / __awaitingApproval /
|
|
3105
|
-
// are made on this object during execution.
|
|
3133
|
+
// __summarizationExhausted / __awaitingApproval / __awaitingUserQuestion /
|
|
3134
|
+
// __structuredOutputParsed are made on this object during execution.
|
|
3106
3135
|
ctx: state.ctx,
|
|
3107
3136
|
agent: state.agent,
|
|
3108
|
-
pendingApprovals
|
|
3137
|
+
pendingApprovals,
|
|
3138
|
+
pendingUserQuestions
|
|
3109
3139
|
};
|
|
3110
3140
|
};
|
|
3111
3141
|
}
|
|
@@ -3571,6 +3601,226 @@ function resolveToolApprovalState(state, resolution) {
|
|
|
3571
3601
|
};
|
|
3572
3602
|
}
|
|
3573
3603
|
|
|
3604
|
+
// src/utils/userQuestions.ts
|
|
3605
|
+
var cloneQuestions = (questions) => Array.isArray(questions) ? questions.map((entry) => ({ ...entry })) : [];
|
|
3606
|
+
function validateAnswers(entry, answers, cancelled) {
|
|
3607
|
+
if (cancelled) {
|
|
3608
|
+
return answers || {};
|
|
3609
|
+
}
|
|
3610
|
+
const allowFreeText = entry.allowFreeText !== false;
|
|
3611
|
+
const out = {};
|
|
3612
|
+
const provided = answers || {};
|
|
3613
|
+
for (const question of entry.questions) {
|
|
3614
|
+
const required = question.required !== false;
|
|
3615
|
+
const key = question.question;
|
|
3616
|
+
const answer = provided[key] ?? provided[question.header || ""];
|
|
3617
|
+
if (!answer) {
|
|
3618
|
+
if (required) {
|
|
3619
|
+
throw new Error(`Missing answer for required question: "${key}".`);
|
|
3620
|
+
}
|
|
3621
|
+
continue;
|
|
3622
|
+
}
|
|
3623
|
+
const values = Array.isArray(answer.values) ? answer.values.filter((v) => typeof v === "string") : [];
|
|
3624
|
+
const freeText = typeof answer.freeText === "string" ? answer.freeText.trim() : "";
|
|
3625
|
+
const notes = typeof answer.notes === "string" ? answer.notes : void 0;
|
|
3626
|
+
if (freeText && !allowFreeText) {
|
|
3627
|
+
throw new Error(
|
|
3628
|
+
`Free-text answers are disabled for this agent (question: "${key}"). Pick one of the provided options.`
|
|
3629
|
+
);
|
|
3630
|
+
}
|
|
3631
|
+
if (values.length === 0 && !freeText) {
|
|
3632
|
+
if (required) {
|
|
3633
|
+
throw new Error(`Question "${key}" requires either a selected option or free-text answer.`);
|
|
3634
|
+
}
|
|
3635
|
+
continue;
|
|
3636
|
+
}
|
|
3637
|
+
if (values.length > 1 && !question.multiSelect) {
|
|
3638
|
+
throw new Error(`Question "${key}" is single-select but received multiple values.`);
|
|
3639
|
+
}
|
|
3640
|
+
if (Array.isArray(question.options) && question.options.length > 0 && values.length > 0) {
|
|
3641
|
+
const allowedValues = new Set(
|
|
3642
|
+
question.options.map((option) => option.value ?? option.label)
|
|
3643
|
+
);
|
|
3644
|
+
for (const value of values) {
|
|
3645
|
+
if (!allowedValues.has(value)) {
|
|
3646
|
+
if (!allowFreeText) {
|
|
3647
|
+
throw new Error(
|
|
3648
|
+
`Value "${value}" is not one of the allowed options for question "${key}".`
|
|
3649
|
+
);
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
out[key] = { values, ...freeText ? { freeText } : {}, ...notes ? { notes } : {} };
|
|
3655
|
+
}
|
|
3656
|
+
return out;
|
|
3657
|
+
}
|
|
3658
|
+
function buildToolResponseContent(entry, answers, cancelled, notes) {
|
|
3659
|
+
if (cancelled) {
|
|
3660
|
+
return JSON.stringify({
|
|
3661
|
+
status: "cancelled",
|
|
3662
|
+
message: notes || "User dismissed the question without answering."
|
|
3663
|
+
});
|
|
3664
|
+
}
|
|
3665
|
+
const payload = {
|
|
3666
|
+
status: "answered",
|
|
3667
|
+
answers: entry.questions.map((question) => {
|
|
3668
|
+
const key = question.question;
|
|
3669
|
+
const ans = answers[key];
|
|
3670
|
+
return {
|
|
3671
|
+
question: key,
|
|
3672
|
+
header: question.header,
|
|
3673
|
+
values: ans?.values ?? [],
|
|
3674
|
+
freeText: ans?.freeText,
|
|
3675
|
+
notes: ans?.notes
|
|
3676
|
+
};
|
|
3677
|
+
}),
|
|
3678
|
+
...notes ? { reviewerNotes: notes } : {}
|
|
3679
|
+
};
|
|
3680
|
+
return JSON.stringify(payload);
|
|
3681
|
+
}
|
|
3682
|
+
function resolveUserQuestionState(state, resolution) {
|
|
3683
|
+
const pending = cloneQuestions(state.pendingUserQuestions);
|
|
3684
|
+
const matchIndex = pending.findIndex(
|
|
3685
|
+
(entry2) => entry2.id === resolution.id || entry2.toolCallId === resolution.id
|
|
3686
|
+
);
|
|
3687
|
+
if (matchIndex === -1) {
|
|
3688
|
+
throw new Error(`Pending user question not found for id: ${resolution.id}`);
|
|
3689
|
+
}
|
|
3690
|
+
const entry = { ...pending[matchIndex] };
|
|
3691
|
+
if (entry.status === "answered" || entry.status === "executed" || entry.status === "cancelled") {
|
|
3692
|
+
throw new Error(`User question ${entry.id} already resolved (status: ${entry.status}).`);
|
|
3693
|
+
}
|
|
3694
|
+
const cancelled = resolution.cancelled === true;
|
|
3695
|
+
const validated = validateAnswers(entry, resolution.answers, cancelled);
|
|
3696
|
+
entry.status = cancelled ? "cancelled" : "answered";
|
|
3697
|
+
entry.answers = validated;
|
|
3698
|
+
entry.cancelled = cancelled || void 0;
|
|
3699
|
+
entry.answeredBy = resolution.answeredBy;
|
|
3700
|
+
entry.notes = resolution.notes;
|
|
3701
|
+
entry.answeredAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3702
|
+
pending[matchIndex] = entry;
|
|
3703
|
+
const ctx = { ...state.ctx || {} };
|
|
3704
|
+
delete ctx.__awaitingUserQuestion;
|
|
3705
|
+
if (ctx.__resumeStage === "tools") {
|
|
3706
|
+
delete ctx.__resumeStage;
|
|
3707
|
+
}
|
|
3708
|
+
ctx.__userQuestionResolved = { id: entry.id, status: entry.status };
|
|
3709
|
+
const toolMessage = {
|
|
3710
|
+
role: "tool",
|
|
3711
|
+
name: "ask_user_question",
|
|
3712
|
+
tool_call_id: entry.toolCallId,
|
|
3713
|
+
content: buildToolResponseContent(entry, validated, cancelled, resolution.notes)
|
|
3714
|
+
};
|
|
3715
|
+
return {
|
|
3716
|
+
...state,
|
|
3717
|
+
pendingUserQuestions: pending,
|
|
3718
|
+
messages: [...state.messages || [], toolMessage],
|
|
3719
|
+
ctx
|
|
3720
|
+
};
|
|
3721
|
+
}
|
|
3722
|
+
var DEFAULT_DESCRIPTION_WITH_FREETEXT = "Pause the agent and surface a structured prompt to the human user when you genuinely cannot proceed without their input. Group up to 4 closely related questions into a single call. Prefer concrete options the user can pick over open-ended free-text \u2014 list `options` whenever you can anticipate the choices. The user may type a custom answer for any question. Do not use this tool for things you can deduce from the conversation, the system prompt, or another tool. After the user answers, their selections come back as the tool result.";
|
|
3723
|
+
var DEFAULT_DESCRIPTION_NO_FREETEXT = "Pause the agent and surface a structured multi-choice prompt to the human user when you genuinely cannot proceed without their input. Group up to 4 closely related questions into a single call. Every question MUST include at least two `options` \u2014 free-text answers are disabled for this agent. Do not use this tool for things you can deduce from the conversation, the system prompt, or another tool. After the user picks, their selections come back as the tool result.";
|
|
3724
|
+
function buildOptionSchema() {
|
|
3725
|
+
return z.object({
|
|
3726
|
+
label: z.string().min(1).describe("Display text the user sees"),
|
|
3727
|
+
value: z.string().min(1).optional().describe("Value returned in the answer; defaults to label"),
|
|
3728
|
+
description: z.string().optional(),
|
|
3729
|
+
preview: z.string().optional().describe("Optional code / ASCII preview rendered when this option is focused")
|
|
3730
|
+
}).strict();
|
|
3731
|
+
}
|
|
3732
|
+
function buildQuestionSchema(allowFreeText) {
|
|
3733
|
+
const optionSchema = buildOptionSchema();
|
|
3734
|
+
const baseShape = {
|
|
3735
|
+
question: z.string().min(1).describe("Full question shown to the user"),
|
|
3736
|
+
header: z.string().max(40).optional().describe("Short chip / tag rendered next to the question (max ~12 chars recommended)"),
|
|
3737
|
+
multiSelect: z.boolean().optional().describe("Allow multiple selections. Default: false"),
|
|
3738
|
+
placeholder: z.string().optional(),
|
|
3739
|
+
required: z.boolean().optional().describe("Default: true")
|
|
3740
|
+
};
|
|
3741
|
+
if (allowFreeText) {
|
|
3742
|
+
return z.object({
|
|
3743
|
+
...baseShape,
|
|
3744
|
+
options: z.array(optionSchema).min(2).max(12).optional()
|
|
3745
|
+
}).strict();
|
|
3746
|
+
}
|
|
3747
|
+
return z.object({
|
|
3748
|
+
...baseShape,
|
|
3749
|
+
options: z.array(optionSchema).min(2).max(12).describe("Required: free-text answers are disabled for this agent")
|
|
3750
|
+
}).strict();
|
|
3751
|
+
}
|
|
3752
|
+
function createAskUserQuestionTool(stateRef, config) {
|
|
3753
|
+
const allowFreeText = config.allowFreeText !== false;
|
|
3754
|
+
const description = config.promptOverride ?? (allowFreeText ? DEFAULT_DESCRIPTION_WITH_FREETEXT : DEFAULT_DESCRIPTION_NO_FREETEXT);
|
|
3755
|
+
const questionSchema = buildQuestionSchema(allowFreeText);
|
|
3756
|
+
const askUser = createTool({
|
|
3757
|
+
name: "ask_user_question",
|
|
3758
|
+
description,
|
|
3759
|
+
schema: z.object({
|
|
3760
|
+
questions: z.array(questionSchema).min(1).max(4).describe("1-4 related questions to ask in a single pause.")
|
|
3761
|
+
}).strict(),
|
|
3762
|
+
func: async ({ questions }) => {
|
|
3763
|
+
const ref = askUser._stateRef || (askUser._stateRef = {});
|
|
3764
|
+
const onEvent = ref.__onEvent;
|
|
3765
|
+
if (!ref.ctx) ref.ctx = {};
|
|
3766
|
+
const ctx = ref.ctx;
|
|
3767
|
+
const toolCallId = ref.__currentToolCallId || `ask_user_${nanoid(6)}`;
|
|
3768
|
+
if (!ref.pendingUserQuestions) ref.pendingUserQuestions = [];
|
|
3769
|
+
const pendingList = ref.pendingUserQuestions;
|
|
3770
|
+
const entry = {
|
|
3771
|
+
id: nanoid(),
|
|
3772
|
+
toolCallId,
|
|
3773
|
+
toolName: "ask_user_question",
|
|
3774
|
+
questions,
|
|
3775
|
+
status: "pending",
|
|
3776
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3777
|
+
allowFreeText
|
|
3778
|
+
};
|
|
3779
|
+
pendingList.push(entry);
|
|
3780
|
+
ctx.__awaitingUserQuestion = {
|
|
3781
|
+
id: entry.id,
|
|
3782
|
+
toolCallId: entry.toolCallId,
|
|
3783
|
+
requestedAt: entry.requestedAt
|
|
3784
|
+
};
|
|
3785
|
+
ctx.__resumeStage = "tools";
|
|
3786
|
+
onEvent?.({
|
|
3787
|
+
type: "user_question",
|
|
3788
|
+
status: "pending",
|
|
3789
|
+
id: entry.id,
|
|
3790
|
+
toolCallId: entry.toolCallId,
|
|
3791
|
+
questions: entry.questions,
|
|
3792
|
+
allowFreeText
|
|
3793
|
+
});
|
|
3794
|
+
recordTraceEvent(ctx.__traceSession, {
|
|
3795
|
+
type: "user_question",
|
|
3796
|
+
label: "Ask User",
|
|
3797
|
+
actor: { scope: "agent", name: "ask_user_question", role: "user_interaction" },
|
|
3798
|
+
status: "success",
|
|
3799
|
+
sections: [
|
|
3800
|
+
{
|
|
3801
|
+
kind: "metadata",
|
|
3802
|
+
label: "Pending Question",
|
|
3803
|
+
data: {
|
|
3804
|
+
id: entry.id,
|
|
3805
|
+
toolCallId: entry.toolCallId,
|
|
3806
|
+
questions: entry.questions,
|
|
3807
|
+
allowFreeText
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
]
|
|
3811
|
+
});
|
|
3812
|
+
return {
|
|
3813
|
+
__awaitingUserQuestion: true,
|
|
3814
|
+
id: entry.id,
|
|
3815
|
+
toolCallId: entry.toolCallId
|
|
3816
|
+
};
|
|
3817
|
+
}
|
|
3818
|
+
});
|
|
3819
|
+
askUser._stateRef = stateRef;
|
|
3820
|
+
askUser.__source = "human-in-the-loop";
|
|
3821
|
+
return askUser;
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3574
3824
|
// src/agent.ts
|
|
3575
3825
|
init_utilTokens();
|
|
3576
3826
|
|
|
@@ -3782,6 +4032,21 @@ function createAgent(opts) {
|
|
|
3782
4032
|
const resolver = createResolverNode();
|
|
3783
4033
|
const agentCore = createAgentCoreNode(opts);
|
|
3784
4034
|
const toolsBase = [...opts.tools ?? []];
|
|
4035
|
+
const askUserConfig = (() => {
|
|
4036
|
+
const raw = opts.humanInTheLoop?.askUser;
|
|
4037
|
+
if (!raw) return void 0;
|
|
4038
|
+
if (raw === true) return { enabled: true, allowFreeText: true };
|
|
4039
|
+
return {
|
|
4040
|
+
enabled: true,
|
|
4041
|
+
allowFreeText: raw.allowFreeText !== false,
|
|
4042
|
+
promptOverride: raw.promptOverride
|
|
4043
|
+
};
|
|
4044
|
+
})();
|
|
4045
|
+
const askUserOnQuestion = typeof opts.humanInTheLoop?.askUser === "object" ? opts.humanInTheLoop?.askUser?.onQuestion : void 0;
|
|
4046
|
+
const askUserStateRef = askUserConfig ? { pendingUserQuestions: void 0, ctx: void 0, __onEvent: void 0, __currentToolCallId: void 0 } : void 0;
|
|
4047
|
+
if (askUserConfig && askUserStateRef) {
|
|
4048
|
+
toolsBase.push(createAskUserQuestionTool(askUserStateRef, askUserConfig));
|
|
4049
|
+
}
|
|
3785
4050
|
const soManager = opts.outputSchema ? new StructuredOutputManager(opts.outputSchema, resolveStrategy(opts.model)) : void 0;
|
|
3786
4051
|
if (soManager) {
|
|
3787
4052
|
const modelCapabilities = getModelCapabilities(opts.model);
|
|
@@ -3826,7 +4091,8 @@ function createAgent(opts) {
|
|
|
3826
4091
|
useTodoList: void 0,
|
|
3827
4092
|
outputSchema: opts.outputSchema,
|
|
3828
4093
|
responseFormat: soManager?.getResponseFormat(),
|
|
3829
|
-
tracing: opts.tracing
|
|
4094
|
+
tracing: opts.tracing,
|
|
4095
|
+
humanInTheLoop: askUserConfig ? { askUser: askUserConfig } : void 0
|
|
3830
4096
|
};
|
|
3831
4097
|
const summarizationThreshold = getActiveSummarizationThreshold(opts);
|
|
3832
4098
|
async function runLoop(initial, config, emit) {
|
|
@@ -4116,6 +4382,7 @@ function createAgent(opts) {
|
|
|
4116
4382
|
state = { ...state, ...await toolsNode(state) };
|
|
4117
4383
|
onProgress?.({ stage: "tools", message: "Tools finished" });
|
|
4118
4384
|
if (state.ctx?.__awaitingApproval) break;
|
|
4385
|
+
if (state.ctx?.__awaitingUserQuestion) break;
|
|
4119
4386
|
if (checkpointIfRequested("after_tools")) break;
|
|
4120
4387
|
if (state.ctx?.__finalizedDueToStructuredOutput) break;
|
|
4121
4388
|
if (reflectNode && resolvedReasoning?.reflection.enabled) {
|
|
@@ -4186,7 +4453,7 @@ function createAgent(opts) {
|
|
|
4186
4453
|
}
|
|
4187
4454
|
const lastAfterLoop = state.messages[state.messages.length - 1];
|
|
4188
4455
|
if (lastAfterLoop?.role === "tool" && !pausedStage) {
|
|
4189
|
-
const isExpectedExit = state.ctx?.__awaitingApproval || state.ctx?.__cancelled || state.ctx?.__finalizedDueToStructuredOutput || state.ctx?.__finalizedDueToToolLimit || state.ctx?.__needsSummarization || state.ctx?.__limitBreached;
|
|
4456
|
+
const isExpectedExit = state.ctx?.__awaitingApproval || state.ctx?.__awaitingUserQuestion || state.ctx?.__cancelled || state.ctx?.__finalizedDueToStructuredOutput || state.ctx?.__finalizedDueToToolLimit || state.ctx?.__needsSummarization || state.ctx?.__limitBreached;
|
|
4190
4457
|
if (!isExpectedExit) {
|
|
4191
4458
|
throw new Error(
|
|
4192
4459
|
"Agent loop terminated with a pending tool response but no subsequent model invocation. This usually indicates a model provider error or exhausted iteration budget."
|
|
@@ -4204,7 +4471,17 @@ function createAgent(opts) {
|
|
|
4204
4471
|
const { setTokenCounter: setTokenCounter2 } = await Promise.resolve().then(() => (init_utilTokens(), utilTokens_exports));
|
|
4205
4472
|
setTokenCounter2(userTokenCounter);
|
|
4206
4473
|
}
|
|
4207
|
-
const
|
|
4474
|
+
const callerOnEvent = config?.onEvent;
|
|
4475
|
+
const onEvent = askUserOnQuestion ? (event) => {
|
|
4476
|
+
if (event && event.type === "user_question") {
|
|
4477
|
+
try {
|
|
4478
|
+
askUserOnQuestion(event);
|
|
4479
|
+
} catch (err) {
|
|
4480
|
+
console.warn("[agent-sdk] humanInTheLoop.askUser.onQuestion error:", err);
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
callerOnEvent?.(event);
|
|
4484
|
+
} : callerOnEvent;
|
|
4208
4485
|
const onProgress = config?.onProgress;
|
|
4209
4486
|
const onStream = config?.onStream;
|
|
4210
4487
|
const streamEnabled = config?.stream === true;
|
|
@@ -4248,6 +4525,7 @@ function createAgent(opts) {
|
|
|
4248
4525
|
metadata: input.metadata,
|
|
4249
4526
|
ctx,
|
|
4250
4527
|
pendingApprovals: input.pendingApprovals || [],
|
|
4528
|
+
pendingUserQuestions: input.pendingUserQuestions || [],
|
|
4251
4529
|
agent: input.agent || runtimeWithInvokeLimits,
|
|
4252
4530
|
usage: input.usage || { perRequest: [], totals: {} }
|
|
4253
4531
|
};
|
|
@@ -4324,11 +4602,13 @@ function createAgent(opts) {
|
|
|
4324
4602
|
return invokeAgent(restoredState, config);
|
|
4325
4603
|
};
|
|
4326
4604
|
const resolveToolApproval = (state, resolution) => resolveToolApprovalState(state, resolution);
|
|
4605
|
+
const resolveUserQuestion = (state, resolution) => resolveUserQuestionState(state, resolution);
|
|
4327
4606
|
const instance = {
|
|
4328
4607
|
invoke: invokeAgent,
|
|
4329
4608
|
snapshot: snapshotState,
|
|
4330
4609
|
resume: resumeAgent,
|
|
4331
4610
|
resolveToolApproval,
|
|
4611
|
+
resolveUserQuestion,
|
|
4332
4612
|
asTool: ({ toolName, description, inputDescription }) => {
|
|
4333
4613
|
const schema = z.object({ input: z.string().describe(inputDescription || "Input for delegated agent") });
|
|
4334
4614
|
const delegatedTool = createTool({
|
|
@@ -5645,7 +5925,20 @@ function createSmartAgent(opts) {
|
|
|
5645
5925
|
const userTools = opts.tools ?? [];
|
|
5646
5926
|
const factoryStateRef = { toolHistory: void 0, toolHistoryArchived: void 0, todoList: void 0, planVersion: 0, adherenceScore: 0 };
|
|
5647
5927
|
const factoryContextTools = createContextTools(factoryStateRef, { planningEnabled, includeGetToolResponse: false });
|
|
5928
|
+
const askUserConfig = (() => {
|
|
5929
|
+
const raw = opts.humanInTheLoop?.askUser;
|
|
5930
|
+
if (!raw) return void 0;
|
|
5931
|
+
if (raw === true) return { enabled: true, allowFreeText: true };
|
|
5932
|
+
return {
|
|
5933
|
+
enabled: true,
|
|
5934
|
+
allowFreeText: raw.allowFreeText !== false,
|
|
5935
|
+
promptOverride: raw.promptOverride
|
|
5936
|
+
};
|
|
5937
|
+
})();
|
|
5648
5938
|
const factoryToolsWithoutRecovery = [...userTools, ...factoryContextTools];
|
|
5939
|
+
if (askUserConfig) {
|
|
5940
|
+
factoryToolsWithoutRecovery.push(createAskUserQuestionTool(factoryStateRef, askUserConfig));
|
|
5941
|
+
}
|
|
5649
5942
|
const soManagerFactory = opts.outputSchema ? new StructuredOutputManager(opts.outputSchema, resolveStrategy(opts.model)) : void 0;
|
|
5650
5943
|
const modelCapabilities = opts.outputSchema ? getModelCapabilities(opts.model) : void 0;
|
|
5651
5944
|
const responseFinalizeTool = soManagerFactory && modelCapabilities?.structuredOutput !== "native" ? soManagerFactory.getResponseTool() : void 0;
|
|
@@ -5655,6 +5948,7 @@ function createSmartAgent(opts) {
|
|
|
5655
5948
|
const recoveryTool = createGetToolResponseTool(ref);
|
|
5656
5949
|
const base2 = [...userTools, ...ctxTools];
|
|
5657
5950
|
if (responseFinalizeTool) base2.push(responseFinalizeTool);
|
|
5951
|
+
if (askUserConfig) base2.push(createAskUserQuestionTool(ref, askUserConfig));
|
|
5658
5952
|
const without = base2;
|
|
5659
5953
|
const withRec = [...without, recoveryTool];
|
|
5660
5954
|
return { stateRef: ref, toolsWithoutRecovery: without, toolsWithRecovery: withRec };
|
|
@@ -5839,6 +6133,7 @@ function createSmartAgent(opts) {
|
|
|
5839
6133
|
snapshot: base.snapshot,
|
|
5840
6134
|
resume: base.resume,
|
|
5841
6135
|
resolveToolApproval: base.resolveToolApproval,
|
|
6136
|
+
resolveUserQuestion: base.resolveUserQuestion,
|
|
5842
6137
|
asTool: base.asTool,
|
|
5843
6138
|
asHandoff: base.asHandoff,
|
|
5844
6139
|
__runtime: base.__runtime
|
|
@@ -8141,6 +8436,6 @@ function createProvider(config) {
|
|
|
8141
8436
|
}
|
|
8142
8437
|
}
|
|
8143
8438
|
|
|
8144
|
-
export { AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, DEFAULT_PROFILE_CONFIGS, GuardrailPhase, InMemoryMemoryStore, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, ProviderError, StructuredOutputManager, ToolBasedStrategy, VertexProvider, agentVerdictRule, buildSystemPrompt, captureSnapshot, codePresenceRule, cognipeerSink, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createCodeGuardrail, createContextSummarizeNode, createContextTools, createGetToolResponseTool, createGuardrail, createJsonGuardrail, createManageTodoTool, createProvider, createRegexGuardrail, createResolverNode, createSmartAgent, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customSink, defaultTokenCounter, emptyUsage, evaluateGuardrails, fileSink, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasToolResponseRecoveryReference, httpSink, isSmartModel, jsonSchemaRule, normalizeSmartAgentOptions, otlpSink, readMemoryFacts, regexRule, resolveMemoryStore, resolveStrategy, resolveToolApprovalState, restoreSnapshot, runSmartAgentEvalHarness, setTokenCounter, startStreamingSession, traceSessionToOtlp, withTools, writeSummaryFactsToMemory };
|
|
8439
|
+
export { AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, DEFAULT_PROFILE_CONFIGS, GuardrailPhase, InMemoryMemoryStore, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, ProviderError, StructuredOutputManager, ToolBasedStrategy, VertexProvider, agentVerdictRule, buildSystemPrompt, captureSnapshot, codePresenceRule, cognipeerSink, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createCodeGuardrail, createContextSummarizeNode, createContextTools, createGetToolResponseTool, createGuardrail, createJsonGuardrail, createManageTodoTool, createProvider, createRegexGuardrail, createResolverNode, createSmartAgent, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customSink, defaultTokenCounter, emptyUsage, evaluateGuardrails, fileSink, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasToolResponseRecoveryReference, httpSink, isSmartModel, jsonSchemaRule, normalizeSmartAgentOptions, otlpSink, readMemoryFacts, regexRule, resolveMemoryStore, resolveStrategy, resolveToolApprovalState, resolveUserQuestionState, restoreSnapshot, runSmartAgentEvalHarness, setTokenCounter, startStreamingSession, traceSessionToOtlp, withTools, writeSummaryFactsToMemory };
|
|
8145
8440
|
//# sourceMappingURL=index.mjs.map
|
|
8146
8441
|
//# sourceMappingURL=index.mjs.map
|