@anvia/core 1.11.1 → 1.13.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.
Files changed (56) hide show
  1. package/README.md +40 -2
  2. package/dist/agent/agent.js +4 -4
  3. package/dist/agent/index.js +7 -7
  4. package/dist/agent/resolved-agent.js +5 -5
  5. package/dist/agent/team/agent-team.js +7 -7
  6. package/dist/agent/team/index.js +7 -7
  7. package/dist/{chunk-7XDM7A3W.js → chunk-22E25UM7.js} +2 -2
  8. package/dist/{chunk-2K7NSWUC.js → chunk-AGOZCYFP.js} +6 -6
  9. package/dist/{chunk-PLJQ4274.js → chunk-CKWIXVXM.js} +3 -3
  10. package/dist/{chunk-GSMLYI4Z.js → chunk-D43A3KOF.js} +3 -3
  11. package/dist/{chunk-DRSKZVC6.js → chunk-ED7RKQHE.js} +2 -2
  12. package/dist/{chunk-TXWNIEZU.js → chunk-HF5SX5BQ.js} +2 -2
  13. package/dist/chunk-IRXAEVEQ.js +105 -0
  14. package/dist/chunk-IRXAEVEQ.js.map +1 -0
  15. package/dist/{chunk-GNBPXJC6.js → chunk-KL652GO5.js} +2 -2
  16. package/dist/{chunk-4IOC4SP6.js → chunk-KLDNHX4Z.js} +4 -4
  17. package/dist/{chunk-SHSSCEGO.js → chunk-MG7JYQN2.js} +2 -2
  18. package/dist/chunk-MG7JYQN2.js.map +1 -0
  19. package/dist/{chunk-WU4ODZKR.js → chunk-OZ2GZHWH.js} +13 -4
  20. package/dist/chunk-OZ2GZHWH.js.map +1 -0
  21. package/dist/{chunk-GI6APIEU.js → chunk-R4AJ2EE3.js} +4 -4
  22. package/dist/evals/advanced-metrics.js +3 -3
  23. package/dist/evals/cli.js +3 -3
  24. package/dist/evals/index.js +7 -7
  25. package/dist/evals/metrics.js +3 -3
  26. package/dist/evals/runner.js +2 -2
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +13 -9
  29. package/dist/internal/agent-runtime/agent-run.js +3 -3
  30. package/dist/internal/agent-runtime/execution.js +1 -1
  31. package/dist/internal/agent-runtime/tool-execution.js +2 -2
  32. package/dist/internal/agent.d.ts +7 -2
  33. package/dist/internal/agent.js +6 -6
  34. package/dist/internal/team-runtime/run.js +6 -6
  35. package/dist/skills/index.js +2 -2
  36. package/dist/skills/load.js +1 -1
  37. package/dist/skills/tools.js +1 -1
  38. package/dist/think-tool-CTuagAtn.d.ts +44 -0
  39. package/dist/tool/index.d.ts +1 -1
  40. package/dist/tool/index.js +5 -1
  41. package/dist/tool/question-tool.js +5 -1
  42. package/package.json +1 -1
  43. package/dist/chunk-MNBKSRS5.js +0 -47
  44. package/dist/chunk-MNBKSRS5.js.map +0 -1
  45. package/dist/chunk-SHSSCEGO.js.map +0 -1
  46. package/dist/chunk-WU4ODZKR.js.map +0 -1
  47. package/dist/think-tool-DJbtUDZm.d.ts +0 -40
  48. /package/dist/{chunk-7XDM7A3W.js.map → chunk-22E25UM7.js.map} +0 -0
  49. /package/dist/{chunk-2K7NSWUC.js.map → chunk-AGOZCYFP.js.map} +0 -0
  50. /package/dist/{chunk-PLJQ4274.js.map → chunk-CKWIXVXM.js.map} +0 -0
  51. /package/dist/{chunk-GSMLYI4Z.js.map → chunk-D43A3KOF.js.map} +0 -0
  52. /package/dist/{chunk-DRSKZVC6.js.map → chunk-ED7RKQHE.js.map} +0 -0
  53. /package/dist/{chunk-TXWNIEZU.js.map → chunk-HF5SX5BQ.js.map} +0 -0
  54. /package/dist/{chunk-GNBPXJC6.js.map → chunk-KL652GO5.js.map} +0 -0
  55. /package/dist/{chunk-4IOC4SP6.js.map → chunk-KLDNHX4Z.js.map} +0 -0
  56. /package/dist/{chunk-GI6APIEU.js.map → chunk-R4AJ2EE3.js.map} +0 -0
package/README.md CHANGED
@@ -46,6 +46,42 @@ if (result.type === "response") console.log(result.output);
46
46
  Replace the sample tool body with your application's data access. Agent outcomes distinguish a
47
47
  response, a guardrail block, and an interaction that needs application input.
48
48
 
49
+ ## Ask the user a question
50
+
51
+ Add `createQuestionTool()` to an agent's `tools` to let it ask for missing information:
52
+
53
+ ```ts
54
+ import {
55
+ createQuestionTool,
56
+ DEFAULT_QUESTION_TOOL_NAME,
57
+ DEFAULT_QUESTION_TOOL_DESCRIPTION,
58
+ } from "@anvia/core/tool";
59
+
60
+ const askUser = createQuestionTool(); // name: "ask_user", with built-in model instructions
61
+ const clarify = createQuestionTool({ name: "clarify" }); // either option can be overridden
62
+ ```
63
+
64
+ The defaults are also exported from `@anvia/core`. The description guides the model to ask only
65
+ when it cannot proceed, batch questions, and use sensible defaults for routine choices.
66
+ Supply nonblank custom names and descriptions. Defaults apply when an option is omitted;
67
+ explicit strings, including blanks, are preserved for compatibility with existing callers.
68
+ New tool calls accept 1–4 questions with unique, nonblank IDs and nonblank text. Optional choices
69
+ must contain 2–4 entries with nonblank labels and unique, nonblank values. Values are trimmed
70
+ before validation. Set `allowCustom: true` to allow answers outside the choices, or omit choices
71
+ for free text. A question without choices cannot set `allowCustom: false`.
72
+ Snake-case IDs, question marks, and mutually exclusive choices are model guidance,
73
+ not additional schema restrictions.
74
+
75
+ The run returns a `type: "interaction"` outcome with a `tool-question` request and a continuation.
76
+ Collect a nonblank answer for every question, then resume with the continuation and
77
+ `{ type: "tool-question", answers: [{ questionId, value }] }`. The model receives
78
+ `{ answers: [...] }` as the tool result. Calling the question tool directly does not prompt a UI;
79
+ your application renders the interaction and supplies the answers.
80
+
81
+ Stored interaction requests and continuations keep their existing parsing rules; the new array
82
+ limits apply only to new tool inputs. See the [interaction guide](../../docs/packages/core.md)
83
+ for the resume protocol.
84
+
49
85
  ## What you can build
50
86
 
51
87
  - Agents with typed tools, approvals, questions, guardrails, and streaming responses.
@@ -66,10 +102,12 @@ streamed reasoning for replay on subsequent turns. Conflicting text, reasoning,
66
102
  fail provider output validation.
67
103
 
68
104
  For recoverable execution, register a supported agent with the experimental
69
- [`@anvia/durable`](../durable/README.md) runtime. Durable tools receive an optional stable
105
+ [`@anvia/durable`](../durable/README.md) runtime. Internal execution protocol 4 adds a synchronous steering checkpoint boundary for
106
+ persisting queued user input and replaying it consistently. Upgrade core and durable together.
107
+ Durable tools receive an optional stable
70
108
  `ToolCallContext.operationId` for external idempotency. Direct execution does not supply it.
71
109
  Durable registrations can opt into persisted streaming with `stream: true`; core execution
72
- protocol version 2 checkpoints validated streamed completions alongside tool results.
110
+ protocol version 4 checkpoints validated streamed completions alongside tool results.
73
111
 
74
112
  ## Learn more
75
113
 
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  Agent
3
- } from "../chunk-TXWNIEZU.js";
4
- import "../chunk-WU4ODZKR.js";
3
+ } from "../chunk-HF5SX5BQ.js";
4
+ import "../chunk-OZ2GZHWH.js";
5
5
  import "../chunk-SXE4J43E.js";
6
- import "../chunk-DRSKZVC6.js";
6
+ import "../chunk-ED7RKQHE.js";
7
7
  import "../chunk-LAIATEUB.js";
8
8
  import "../chunk-3F6ZY63S.js";
9
9
  import "../chunk-ZWYMXBGB.js";
@@ -15,7 +15,7 @@ import "../chunk-5ZM5DB3O.js";
15
15
  import "../chunk-5IURMWFN.js";
16
16
  import "../chunk-2NLINXRF.js";
17
17
  import "../chunk-JMJFK3A4.js";
18
- import "../chunk-MNBKSRS5.js";
18
+ import "../chunk-IRXAEVEQ.js";
19
19
  import "../chunk-CASF2TDK.js";
20
20
  import "../chunk-4AW2633B.js";
21
21
  import "../chunk-YNA3UR42.js";
@@ -1,9 +1,9 @@
1
1
  import "../chunk-53TPAXYR.js";
2
2
  import {
3
3
  AgentTeam
4
- } from "../chunk-GSMLYI4Z.js";
4
+ } from "../chunk-D43A3KOF.js";
5
5
  import "../chunk-X6WS3XWL.js";
6
- import "../chunk-PLJQ4274.js";
6
+ import "../chunk-CKWIXVXM.js";
7
7
  import "../chunk-PIMD4DYG.js";
8
8
  import "../chunk-FSBDE6RF.js";
9
9
  import "../chunk-3TAQXJBC.js";
@@ -12,13 +12,13 @@ import {
12
12
  AgentTeamInteractionError,
13
13
  AgentTeamLimitError
14
14
  } from "../chunk-ENZ2XX27.js";
15
- import "../chunk-7XDM7A3W.js";
15
+ import "../chunk-22E25UM7.js";
16
16
  import {
17
17
  Agent
18
- } from "../chunk-TXWNIEZU.js";
19
- import "../chunk-WU4ODZKR.js";
18
+ } from "../chunk-HF5SX5BQ.js";
19
+ import "../chunk-OZ2GZHWH.js";
20
20
  import "../chunk-SXE4J43E.js";
21
- import "../chunk-DRSKZVC6.js";
21
+ import "../chunk-ED7RKQHE.js";
22
22
  import "../chunk-LAIATEUB.js";
23
23
  import "../chunk-3F6ZY63S.js";
24
24
  import "../chunk-ZWYMXBGB.js";
@@ -30,7 +30,7 @@ import "../chunk-5ZM5DB3O.js";
30
30
  import "../chunk-5IURMWFN.js";
31
31
  import "../chunk-2NLINXRF.js";
32
32
  import "../chunk-JMJFK3A4.js";
33
- import "../chunk-MNBKSRS5.js";
33
+ import "../chunk-IRXAEVEQ.js";
34
34
  import "../chunk-CASF2TDK.js";
35
35
  import "../chunk-4AW2633B.js";
36
36
  import "../chunk-YNA3UR42.js";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  createResolvedAgent,
3
3
  getResolvedAgentOptions
4
- } from "../chunk-7XDM7A3W.js";
5
- import "../chunk-TXWNIEZU.js";
6
- import "../chunk-WU4ODZKR.js";
4
+ } from "../chunk-22E25UM7.js";
5
+ import "../chunk-HF5SX5BQ.js";
6
+ import "../chunk-OZ2GZHWH.js";
7
7
  import "../chunk-SXE4J43E.js";
8
- import "../chunk-DRSKZVC6.js";
8
+ import "../chunk-ED7RKQHE.js";
9
9
  import "../chunk-LAIATEUB.js";
10
10
  import "../chunk-3F6ZY63S.js";
11
11
  import "../chunk-ZWYMXBGB.js";
@@ -17,7 +17,7 @@ import "../chunk-5ZM5DB3O.js";
17
17
  import "../chunk-5IURMWFN.js";
18
18
  import "../chunk-2NLINXRF.js";
19
19
  import "../chunk-JMJFK3A4.js";
20
- import "../chunk-MNBKSRS5.js";
20
+ import "../chunk-IRXAEVEQ.js";
21
21
  import "../chunk-CASF2TDK.js";
22
22
  import "../chunk-4AW2633B.js";
23
23
  import "../chunk-YNA3UR42.js";
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  AgentTeam
3
- } from "../../chunk-GSMLYI4Z.js";
3
+ } from "../../chunk-D43A3KOF.js";
4
4
  import "../../chunk-X6WS3XWL.js";
5
- import "../../chunk-PLJQ4274.js";
5
+ import "../../chunk-CKWIXVXM.js";
6
6
  import "../../chunk-PIMD4DYG.js";
7
7
  import "../../chunk-FSBDE6RF.js";
8
8
  import "../../chunk-3TAQXJBC.js";
9
9
  import "../../chunk-X35O3AQG.js";
10
10
  import "../../chunk-ENZ2XX27.js";
11
- import "../../chunk-7XDM7A3W.js";
12
- import "../../chunk-TXWNIEZU.js";
13
- import "../../chunk-WU4ODZKR.js";
11
+ import "../../chunk-22E25UM7.js";
12
+ import "../../chunk-HF5SX5BQ.js";
13
+ import "../../chunk-OZ2GZHWH.js";
14
14
  import "../../chunk-SXE4J43E.js";
15
- import "../../chunk-DRSKZVC6.js";
15
+ import "../../chunk-ED7RKQHE.js";
16
16
  import "../../chunk-LAIATEUB.js";
17
17
  import "../../chunk-3F6ZY63S.js";
18
18
  import "../../chunk-ZWYMXBGB.js";
@@ -24,7 +24,7 @@ import "../../chunk-5ZM5DB3O.js";
24
24
  import "../../chunk-5IURMWFN.js";
25
25
  import "../../chunk-2NLINXRF.js";
26
26
  import "../../chunk-JMJFK3A4.js";
27
- import "../../chunk-MNBKSRS5.js";
27
+ import "../../chunk-IRXAEVEQ.js";
28
28
  import "../../chunk-CASF2TDK.js";
29
29
  import "../../chunk-4AW2633B.js";
30
30
  import "../../chunk-YNA3UR42.js";
@@ -1,9 +1,9 @@
1
1
  import "../../chunk-53TPAXYR.js";
2
2
  import {
3
3
  AgentTeam
4
- } from "../../chunk-GSMLYI4Z.js";
4
+ } from "../../chunk-D43A3KOF.js";
5
5
  import "../../chunk-X6WS3XWL.js";
6
- import "../../chunk-PLJQ4274.js";
6
+ import "../../chunk-CKWIXVXM.js";
7
7
  import "../../chunk-PIMD4DYG.js";
8
8
  import "../../chunk-FSBDE6RF.js";
9
9
  import "../../chunk-3TAQXJBC.js";
@@ -12,11 +12,11 @@ import {
12
12
  AgentTeamInteractionError,
13
13
  AgentTeamLimitError
14
14
  } from "../../chunk-ENZ2XX27.js";
15
- import "../../chunk-7XDM7A3W.js";
16
- import "../../chunk-TXWNIEZU.js";
17
- import "../../chunk-WU4ODZKR.js";
15
+ import "../../chunk-22E25UM7.js";
16
+ import "../../chunk-HF5SX5BQ.js";
17
+ import "../../chunk-OZ2GZHWH.js";
18
18
  import "../../chunk-SXE4J43E.js";
19
- import "../../chunk-DRSKZVC6.js";
19
+ import "../../chunk-ED7RKQHE.js";
20
20
  import "../../chunk-LAIATEUB.js";
21
21
  import "../../chunk-3F6ZY63S.js";
22
22
  import "../../chunk-ZWYMXBGB.js";
@@ -28,7 +28,7 @@ import "../../chunk-5ZM5DB3O.js";
28
28
  import "../../chunk-5IURMWFN.js";
29
29
  import "../../chunk-2NLINXRF.js";
30
30
  import "../../chunk-JMJFK3A4.js";
31
- import "../../chunk-MNBKSRS5.js";
31
+ import "../../chunk-IRXAEVEQ.js";
32
32
  import "../../chunk-CASF2TDK.js";
33
33
  import "../../chunk-4AW2633B.js";
34
34
  import "../../chunk-YNA3UR42.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Agent
3
- } from "./chunk-TXWNIEZU.js";
3
+ } from "./chunk-HF5SX5BQ.js";
4
4
  import {
5
5
  getAgentToolState
6
6
  } from "./chunk-A7BXVZXZ.js";
@@ -45,4 +45,4 @@ export {
45
45
  createResolvedAgent,
46
46
  getResolvedAgentOptions
47
47
  };
48
- //# sourceMappingURL=chunk-7XDM7A3W.js.map
48
+ //# sourceMappingURL=chunk-22E25UM7.js.map
@@ -1,3 +1,6 @@
1
+ import {
2
+ extract
3
+ } from "./chunk-VCOGUS3Q.js";
1
4
  import {
2
5
  resolveActual,
3
6
  resolveActualText,
@@ -5,15 +8,12 @@ import {
5
8
  resolveJudgePrompt
6
9
  } from "./chunk-ZPXOBQDS.js";
7
10
  import {
8
- extract
9
- } from "./chunk-VCOGUS3Q.js";
11
+ EvalOutcome
12
+ } from "./chunk-EJR6VVB3.js";
10
13
  import {
11
14
  evalValuesEqual,
12
15
  formatValue
13
16
  } from "./chunk-ZYXMWEL4.js";
14
- import {
15
- EvalOutcome
16
- } from "./chunk-EJR6VVB3.js";
17
17
  import {
18
18
  embedText
19
19
  } from "./chunk-YCTXTOOQ.js";
@@ -328,4 +328,4 @@ export {
328
328
  llmJudge,
329
329
  llmScore
330
330
  };
331
- //# sourceMappingURL=chunk-2K7NSWUC.js.map
331
+ //# sourceMappingURL=chunk-AGOZCYFP.js.map
@@ -19,10 +19,10 @@ import {
19
19
  import {
20
20
  createResolvedAgent,
21
21
  getResolvedAgentOptions
22
- } from "./chunk-7XDM7A3W.js";
22
+ } from "./chunk-22E25UM7.js";
23
23
  import {
24
24
  AgentRun
25
- } from "./chunk-WU4ODZKR.js";
25
+ } from "./chunk-OZ2GZHWH.js";
26
26
  import {
27
27
  withInternalAgentRunOptions
28
28
  } from "./chunk-7FBSGD6E.js";
@@ -619,4 +619,4 @@ var TeamRun = class {
619
619
  export {
620
620
  TeamRun
621
621
  };
622
- //# sourceMappingURL=chunk-PLJQ4274.js.map
622
+ //# sourceMappingURL=chunk-CKWIXVXM.js.map
@@ -3,13 +3,13 @@ import {
3
3
  } from "./chunk-X6WS3XWL.js";
4
4
  import {
5
5
  TeamRun
6
- } from "./chunk-PLJQ4274.js";
6
+ } from "./chunk-CKWIXVXM.js";
7
7
  import {
8
8
  TeamStream
9
9
  } from "./chunk-3TAQXJBC.js";
10
10
  import {
11
11
  Agent
12
- } from "./chunk-TXWNIEZU.js";
12
+ } from "./chunk-HF5SX5BQ.js";
13
13
  import {
14
14
  assertPositiveSafeInteger
15
15
  } from "./chunk-NPJ2T3L5.js";
@@ -104,4 +104,4 @@ var AgentTeam = class {
104
104
  export {
105
105
  AgentTeam
106
106
  };
107
- //# sourceMappingURL=chunk-GSMLYI4Z.js.map
107
+ //# sourceMappingURL=chunk-D43A3KOF.js.map
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-2NLINXRF.js";
8
8
  import {
9
9
  isQuestionTool
10
- } from "./chunk-MNBKSRS5.js";
10
+ } from "./chunk-IRXAEVEQ.js";
11
11
  import {
12
12
  runControl,
13
13
  toolCallControl
@@ -967,4 +967,4 @@ function agentToolEventPayload(toolCall, internalCallId, event) {
967
967
  export {
968
968
  ToolCallExecutor
969
969
  };
970
- //# sourceMappingURL=chunk-DRSKZVC6.js.map
970
+ //# sourceMappingURL=chunk-ED7RKQHE.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AgentRun
3
- } from "./chunk-WU4ODZKR.js";
3
+ } from "./chunk-OZ2GZHWH.js";
4
4
  import {
5
5
  normalizeMemoryScope
6
6
  } from "./chunk-LAIATEUB.js";
@@ -155,4 +155,4 @@ var Agent = class {
155
155
  export {
156
156
  Agent
157
157
  };
158
- //# sourceMappingURL=chunk-TXWNIEZU.js.map
158
+ //# sourceMappingURL=chunk-HF5SX5BQ.js.map
@@ -0,0 +1,105 @@
1
+ import {
2
+ createTool
3
+ } from "./chunk-MEFGXAKJ.js";
4
+
5
+ // src/tool/question-tool.ts
6
+ import { z } from "zod";
7
+ var questionToolMarker = /* @__PURE__ */ Symbol("anvia.question-tool");
8
+ var DEFAULT_QUESTION_TOOL_NAME = "ask_user";
9
+ var DEFAULT_QUESTION_TOOL_DESCRIPTION = `Ask the user questions and wait for their answers before continuing.
10
+
11
+ Use this tool only when you cannot continue without the user's input:
12
+ - The request is ambiguous, and different readings would lead to clearly different results.
13
+ - A decision belongs to the user: a preference, a tradeoff, or something that is hard to undo.
14
+ - Information you need is missing and you cannot find it with your other tools or work it out from the conversation.
15
+
16
+ Do not use it:
17
+ - For facts you can look up with your other tools, or work out from the conversation.
18
+ - To ask permission for routine steps the user has already asked for.
19
+ - To check whether your answer or plan is good. Finish the work and let the user react.
20
+ - For choices with a sensible default. Pick it, and mention the choice in your reply.
21
+
22
+ How to ask:
23
+ - Put every question you need into one call instead of calling the tool repeatedly. Ask no more than 4 questions per call.
24
+ - Give each question a short, unique \`id\` in snake_case.
25
+ - Write \`text\` as one complete, self-contained question that ends with a question mark.
26
+ - When there is a known set of reasonable answers, give 2\u20134 \`choices\` with a short \`label\` and a stable \`value\`. Make the choices mutually exclusive. If you recommend one, list it first and add " (recommended)" to its label.
27
+ - Set \`allowCustom: true\` when the user might want an answer outside the list. Leave out \`choices\` for open-ended questions. Do not add an "Other" choice.
28
+
29
+ After you get the answers:
30
+ - Each answer has a \`questionId\` and a \`value\` (the chosen value or the user's free text).
31
+ - Follow the answers. Do not ask the same question again unless an answer is unclear or contradicts another one.`;
32
+ function createQuestionTool(options = {}) {
33
+ const tool = createTool({
34
+ name: options.name ?? DEFAULT_QUESTION_TOOL_NAME,
35
+ description: options.description ?? DEFAULT_QUESTION_TOOL_DESCRIPTION,
36
+ inputSchema: z.object({
37
+ questions: z.array(
38
+ z.object({
39
+ id: z.string().trim().min(1, "Question IDs must not be empty."),
40
+ text: z.string().trim().min(1, "Question text must not be empty."),
41
+ choices: z.array(
42
+ z.object({
43
+ label: z.string().trim().min(1, "Question choice labels must not be empty."),
44
+ value: z.string().trim().min(1, "Question choice values must not be empty.")
45
+ }).strict()
46
+ ).min(2, "Questions with choices must have at least 2 choices.").max(4, "Questions must have no more than 4 choices.").superRefine((choices, context) => {
47
+ const values = /* @__PURE__ */ new Set();
48
+ for (const [index, choice] of choices.entries()) {
49
+ if (values.has(choice.value)) {
50
+ context.addIssue({
51
+ code: "custom",
52
+ message: "Question choice values must be unique.",
53
+ path: [index, "value"]
54
+ });
55
+ }
56
+ values.add(choice.value);
57
+ }
58
+ }).optional(),
59
+ allowCustom: z.boolean().optional()
60
+ }).strict().superRefine((question, context) => {
61
+ if (question.choices === void 0 && question.allowCustom === false) {
62
+ context.addIssue({
63
+ code: "custom",
64
+ message: "A free-text question cannot disable custom answers.",
65
+ path: ["allowCustom"]
66
+ });
67
+ }
68
+ })
69
+ ).min(1, "Provide at least 1 question.").max(4, "Ask no more than 4 questions per call.").superRefine((questions, context) => {
70
+ const ids = /* @__PURE__ */ new Set();
71
+ for (const [index, question] of questions.entries()) {
72
+ if (ids.has(question.id)) {
73
+ context.addIssue({
74
+ code: "custom",
75
+ message: "Question IDs must be unique.",
76
+ path: [index, "id"]
77
+ });
78
+ }
79
+ ids.add(question.id);
80
+ }
81
+ })
82
+ }).strict(),
83
+ execute() {
84
+ throw new Error("Question tools can only be resolved through an Agent interaction.");
85
+ }
86
+ });
87
+ Object.defineProperty(tool, questionToolMarker, {
88
+ configurable: false,
89
+ enumerable: false,
90
+ value: true,
91
+ writable: false
92
+ });
93
+ return tool;
94
+ }
95
+ function isQuestionTool(tool) {
96
+ return typeof tool === "object" && tool !== null && questionToolMarker in tool;
97
+ }
98
+
99
+ export {
100
+ DEFAULT_QUESTION_TOOL_NAME,
101
+ DEFAULT_QUESTION_TOOL_DESCRIPTION,
102
+ createQuestionTool,
103
+ isQuestionTool
104
+ };
105
+ //# sourceMappingURL=chunk-IRXAEVEQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tool/question-tool.ts"],"sourcesContent":["import { z } from \"zod\";\nimport type { AgentQuestionAnswer, AgentQuestionPrompt } from \"../agent/interactions\";\nimport { createTool } from \"./create-tool\";\nimport type { Tool } from \"./tool\";\n\nconst questionToolMarker = Symbol(\"anvia.question-tool\");\n\nexport const DEFAULT_QUESTION_TOOL_NAME = \"ask_user\";\n\nexport const DEFAULT_QUESTION_TOOL_DESCRIPTION = `Ask the user questions and wait for their answers before continuing.\n\nUse this tool only when you cannot continue without the user's input:\n- The request is ambiguous, and different readings would lead to clearly different results.\n- A decision belongs to the user: a preference, a tradeoff, or something that is hard to undo.\n- Information you need is missing and you cannot find it with your other tools or work it out from the conversation.\n\nDo not use it:\n- For facts you can look up with your other tools, or work out from the conversation.\n- To ask permission for routine steps the user has already asked for.\n- To check whether your answer or plan is good. Finish the work and let the user react.\n- For choices with a sensible default. Pick it, and mention the choice in your reply.\n\nHow to ask:\n- Put every question you need into one call instead of calling the tool repeatedly. Ask no more than 4 questions per call.\n- Give each question a short, unique \\`id\\` in snake_case.\n- Write \\`text\\` as one complete, self-contained question that ends with a question mark.\n- When there is a known set of reasonable answers, give 2–4 \\`choices\\` with a short \\`label\\` and a stable \\`value\\`. Make the choices mutually exclusive. If you recommend one, list it first and add \" (recommended)\" to its label.\n- Set \\`allowCustom: true\\` when the user might want an answer outside the list. Leave out \\`choices\\` for open-ended questions. Do not add an \"Other\" choice.\n\nAfter you get the answers:\n- Each answer has a \\`questionId\\` and a \\`value\\` (the chosen value or the user's free text).\n- Follow the answers. Do not ask the same question again unless an answer is unclear or contradicts another one.`;\n\nexport type QuestionToolInput = {\n questions: readonly AgentQuestionPrompt[];\n};\n\nexport type QuestionToolOutput = {\n answers: readonly AgentQuestionAnswer[];\n};\n\nexport type CreateQuestionToolOptions = {\n /** Defaults when omitted. Supply a nonblank name; explicit strings are preserved. */\n name?: string;\n /** Defaults when omitted. Supply nonblank instructions; explicit strings are preserved. */\n description?: string;\n};\n\ntype MarkedQuestionTool = Tool<QuestionToolInput, QuestionToolOutput> & {\n readonly [questionToolMarker]: true;\n};\n\nexport function createQuestionTool(\n options: CreateQuestionToolOptions = {},\n): Tool<QuestionToolInput, QuestionToolOutput> {\n const tool = createTool({\n name: options.name ?? DEFAULT_QUESTION_TOOL_NAME,\n description: options.description ?? DEFAULT_QUESTION_TOOL_DESCRIPTION,\n inputSchema: z\n .object({\n questions: z\n .array(\n z\n .object({\n id: z.string().trim().min(1, \"Question IDs must not be empty.\"),\n text: z.string().trim().min(1, \"Question text must not be empty.\"),\n choices: z\n .array(\n z\n .object({\n label: z\n .string()\n .trim()\n .min(1, \"Question choice labels must not be empty.\"),\n value: z\n .string()\n .trim()\n .min(1, \"Question choice values must not be empty.\"),\n })\n .strict(),\n )\n .min(2, \"Questions with choices must have at least 2 choices.\")\n .max(4, \"Questions must have no more than 4 choices.\")\n .superRefine((choices, context) => {\n const values = new Set<string>();\n for (const [index, choice] of choices.entries()) {\n if (values.has(choice.value)) {\n context.addIssue({\n code: \"custom\",\n message: \"Question choice values must be unique.\",\n path: [index, \"value\"],\n });\n }\n values.add(choice.value);\n }\n })\n .optional(),\n allowCustom: z.boolean().optional(),\n })\n .strict()\n .superRefine((question, context) => {\n if (question.choices === undefined && question.allowCustom === false) {\n context.addIssue({\n code: \"custom\",\n message: \"A free-text question cannot disable custom answers.\",\n path: [\"allowCustom\"],\n });\n }\n }),\n )\n .min(1, \"Provide at least 1 question.\")\n .max(4, \"Ask no more than 4 questions per call.\")\n .superRefine((questions, context) => {\n const ids = new Set<string>();\n for (const [index, question] of questions.entries()) {\n if (ids.has(question.id)) {\n context.addIssue({\n code: \"custom\",\n message: \"Question IDs must be unique.\",\n path: [index, \"id\"],\n });\n }\n ids.add(question.id);\n }\n }),\n })\n .strict(),\n execute(): never {\n throw new Error(\"Question tools can only be resolved through an Agent interaction.\");\n },\n }) as unknown as MarkedQuestionTool;\n Object.defineProperty(tool, questionToolMarker, {\n configurable: false,\n enumerable: false,\n value: true,\n writable: false,\n });\n return tool;\n}\n\nexport function isQuestionTool(tool: unknown): tool is Tool<QuestionToolInput, QuestionToolOutput> {\n return typeof tool === \"object\" && tool !== null && questionToolMarker in tool;\n}\n"],"mappings":";;;;;AAAA,SAAS,SAAS;AAKlB,IAAM,qBAAqB,uBAAO,qBAAqB;AAEhD,IAAM,6BAA6B;AAEnC,IAAM,oCAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2C1C,SAAS,mBACd,UAAqC,CAAC,GACO;AAC7C,QAAM,OAAO,WAAW;AAAA,IACtB,MAAM,QAAQ,QAAQ;AAAA,IACtB,aAAa,QAAQ,eAAe;AAAA,IACpC,aAAa,EACV,OAAO;AAAA,MACN,WAAW,EACR;AAAA,QACC,EACG,OAAO;AAAA,UACN,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,iCAAiC;AAAA,UAC9D,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,kCAAkC;AAAA,UACjE,SAAS,EACN;AAAA,YACC,EACG,OAAO;AAAA,cACN,OAAO,EACJ,OAAO,EACP,KAAK,EACL,IAAI,GAAG,2CAA2C;AAAA,cACrD,OAAO,EACJ,OAAO,EACP,KAAK,EACL,IAAI,GAAG,2CAA2C;AAAA,YACvD,CAAC,EACA,OAAO;AAAA,UACZ,EACC,IAAI,GAAG,sDAAsD,EAC7D,IAAI,GAAG,6CAA6C,EACpD,YAAY,CAAC,SAAS,YAAY;AACjC,kBAAM,SAAS,oBAAI,IAAY;AAC/B,uBAAW,CAAC,OAAO,MAAM,KAAK,QAAQ,QAAQ,GAAG;AAC/C,kBAAI,OAAO,IAAI,OAAO,KAAK,GAAG;AAC5B,wBAAQ,SAAS;AAAA,kBACf,MAAM;AAAA,kBACN,SAAS;AAAA,kBACT,MAAM,CAAC,OAAO,OAAO;AAAA,gBACvB,CAAC;AAAA,cACH;AACA,qBAAO,IAAI,OAAO,KAAK;AAAA,YACzB;AAAA,UACF,CAAC,EACA,SAAS;AAAA,UACZ,aAAa,EAAE,QAAQ,EAAE,SAAS;AAAA,QACpC,CAAC,EACA,OAAO,EACP,YAAY,CAAC,UAAU,YAAY;AAClC,cAAI,SAAS,YAAY,UAAa,SAAS,gBAAgB,OAAO;AACpE,oBAAQ,SAAS;AAAA,cACf,MAAM;AAAA,cACN,SAAS;AAAA,cACT,MAAM,CAAC,aAAa;AAAA,YACtB,CAAC;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACL,EACC,IAAI,GAAG,8BAA8B,EACrC,IAAI,GAAG,wCAAwC,EAC/C,YAAY,CAAC,WAAW,YAAY;AACnC,cAAM,MAAM,oBAAI,IAAY;AAC5B,mBAAW,CAAC,OAAO,QAAQ,KAAK,UAAU,QAAQ,GAAG;AACnD,cAAI,IAAI,IAAI,SAAS,EAAE,GAAG;AACxB,oBAAQ,SAAS;AAAA,cACf,MAAM;AAAA,cACN,SAAS;AAAA,cACT,MAAM,CAAC,OAAO,IAAI;AAAA,YACpB,CAAC;AAAA,UACH;AACA,cAAI,IAAI,SAAS,EAAE;AAAA,QACrB;AAAA,MACF,CAAC;AAAA,IACL,CAAC,EACA,OAAO;AAAA,IACV,UAAiB;AACf,YAAM,IAAI,MAAM,mEAAmE;AAAA,IACrF;AAAA,EACF,CAAC;AACD,SAAO,eAAe,MAAM,oBAAoB;AAAA,IAC9C,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,UAAU;AAAA,EACZ,CAAC;AACD,SAAO;AACT;AAEO,SAAS,eAAe,MAAoE;AACjG,SAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,sBAAsB;AAC5E;","names":[]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runEvalSuite
3
- } from "./chunk-4IOC4SP6.js";
3
+ } from "./chunk-KLDNHX4Z.js";
4
4
 
5
5
  // src/evals/cli.ts
6
6
  var EvalAssertionError = class extends Error {
@@ -352,4 +352,4 @@ export {
352
352
  assertEvalOutcomes,
353
353
  runEvalCli
354
354
  };
355
- //# sourceMappingURL=chunk-GNBPXJC6.js.map
355
+ //# sourceMappingURL=chunk-KL652GO5.js.map
@@ -1,9 +1,6 @@
1
1
  import {
2
2
  defaultEvalTraceSelector
3
3
  } from "./chunk-PHLGGRHC.js";
4
- import {
5
- errorMessage
6
- } from "./chunk-ZYXMWEL4.js";
7
4
  import {
8
5
  EvalOutcome
9
6
  } from "./chunk-EJR6VVB3.js";
@@ -14,6 +11,9 @@ import {
14
11
  createConcurrencyLimiter,
15
12
  createEvalCaseSignal
16
13
  } from "./chunk-4OSA3MMA.js";
14
+ import {
15
+ errorMessage
16
+ } from "./chunk-ZYXMWEL4.js";
17
17
  import {
18
18
  Usage
19
19
  } from "./chunk-HJ6KTQTZ.js";
@@ -660,4 +660,4 @@ export {
660
660
  EvalFailFastError,
661
661
  runEvalSuite
662
662
  };
663
- //# sourceMappingURL=chunk-4IOC4SP6.js.map
663
+ //# sourceMappingURL=chunk-KLDNHX4Z.js.map
@@ -1,7 +1,7 @@
1
1
  // src/internal/agent-runtime/execution.ts
2
- var AGENT_RUN_EXECUTION_VERSION = 3;
2
+ var AGENT_RUN_EXECUTION_VERSION = 4;
3
3
 
4
4
  export {
5
5
  AGENT_RUN_EXECUTION_VERSION
6
6
  };
7
- //# sourceMappingURL=chunk-SHSSCEGO.js.map
7
+ //# sourceMappingURL=chunk-MG7JYQN2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/agent-runtime/execution.ts"],"sourcesContent":["import type { PreparedLoopContext, LoopContextCheckpoint } from \"./loop-context\";\nimport type {\n CompletionRequest,\n CompletionResponse,\n ToolCallPart,\n Message,\n UserMessage,\n} from \"../../completion\";\nimport type { NormalizedToolOutput, ToolCallContext } from \"../../tool\";\nimport type { AgentStreamEvent } from \"../../agent/run-types\";\n\n/** Runtime capability marker: older core versions must fail before accepting durable work. */\nexport const AGENT_RUN_EXECUTION_VERSION = 4;\n\n/** Normalized generation progress; never includes raw provider responses. */\nexport type AgentCompletionStreamEvent = Extract<\n AgentStreamEvent<unknown, unknown>,\n {\n type:\n | \"text_delta\"\n | \"reasoning_delta\"\n | \"tool_call_delta\"\n | \"tool_call\"\n | \"source\"\n | \"provider_tool_call\";\n }\n>;\n\nexport type AgentCompletionStream = AsyncGenerator<AgentCompletionStreamEvent, CompletionResponse>;\n\nexport type AgentToolExecutionResult =\n | { output: NormalizedToolOutput; failed: false }\n | { output: NormalizedToolOutput; failed: true; error: unknown };\n\n/** Internal persistence boundary used by execution runtimes. Callbacks own external effects. */\nexport interface AgentRunExecution {\n /** Synchronously checkpoint queued input at a safe boundary, including empty/closing drains. */\n drainSteering?(turn: number, closing: boolean): { id: string; messages: UserMessage[] }[];\n /** Persist the context selected before each model call, including skipped compaction decisions. */\n prepareMessages?(\n turn: number,\n messages: readonly Message[],\n checkpoint?: LoopContextCheckpoint,\n ): Promise<PreparedLoopContext>;\n completion(\n turn: number,\n request: CompletionRequest,\n execute: () => Promise<CompletionResponse>,\n ): Promise<CompletionResponse>;\n streamCompletion?(\n turn: number,\n request: CompletionRequest,\n execute: () => AgentCompletionStream,\n ): AgentCompletionStream;\n tool(\n call: { turn: number; toolCall: ToolCallPart; args: string },\n execute: (context?: Pick<ToolCallContext, \"operationId\">) => Promise<AgentToolExecutionResult>,\n ): Promise<AgentToolExecutionResult>;\n}\n"],"mappings":";AAYO,IAAM,8BAA8B;","names":[]}
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-SXE4J43E.js";
7
7
  import {
8
8
  ToolCallExecutor
9
- } from "./chunk-DRSKZVC6.js";
9
+ } from "./chunk-ED7RKQHE.js";
10
10
  import {
11
11
  normalizeMemoryScope
12
12
  } from "./chunk-LAIATEUB.js";
@@ -41,7 +41,7 @@ import {
41
41
  } from "./chunk-5IURMWFN.js";
42
42
  import {
43
43
  isQuestionTool
44
- } from "./chunk-MNBKSRS5.js";
44
+ } from "./chunk-IRXAEVEQ.js";
45
45
  import {
46
46
  startAgentRunObservers
47
47
  } from "./chunk-YNA3UR42.js";
@@ -384,6 +384,9 @@ var AgentRun = class _AgentRun {
384
384
  throw error;
385
385
  }
386
386
  }
387
+ if (this.continuationState === void 0 && this.execution?.drainSteering !== void 0) {
388
+ await this.drainSteeringMessages(runId, 0, newMessages, pendingTurnMessages);
389
+ }
387
390
  while (currentTurns <= this.maxTurnCount) {
388
391
  const prompt = newMessages.at(-1);
389
392
  if (prompt === void 0) {
@@ -695,6 +698,9 @@ var AgentRun = class _AgentRun {
695
698
  throw error;
696
699
  }
697
700
  }
701
+ if (this.continuationState === void 0 && this.execution?.drainSteering !== void 0) {
702
+ await this.drainSteeringMessages(runId, 0, newMessages, pendingTurnMessages);
703
+ }
698
704
  while (currentTurns <= this.maxTurnCount) {
699
705
  const prompt = newMessages.at(-1);
700
706
  if (prompt === void 0) {
@@ -1912,7 +1918,10 @@ var AgentRun = class _AgentRun {
1912
1918
  return this.activeHook?.onCompletionResponse !== void 0 || this.activeMiddlewares().some((middleware) => middleware.onCompletionResponse !== void 0);
1913
1919
  }
1914
1920
  async drainSteeringMessages(runId, turn, newMessages, pendingTurnMessages, options = {}) {
1915
- const receipts = this.steeringMessages.splice(0);
1921
+ const receipts = [
1922
+ ...this.execution?.drainSteering?.(turn, options.closeWhenEmpty === true) ?? [],
1923
+ ...this.steeringMessages.splice(0)
1924
+ ];
1916
1925
  if (receipts.length === 0) {
1917
1926
  if (options.closeWhenEmpty === true) {
1918
1927
  this.runState = "closing";
@@ -2384,4 +2393,4 @@ function observerRunEnd(outcome) {
2384
2393
  export {
2385
2394
  AgentRun
2386
2395
  };
2387
- //# sourceMappingURL=chunk-WU4ODZKR.js.map
2396
+ //# sourceMappingURL=chunk-OZ2GZHWH.js.map