@vibes.diy/api-svc 14.0.20 → 14.0.22

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 (102) hide show
  1. package/create-handler.js +12 -0
  2. package/create-handler.js.map +1 -1
  3. package/evento-handler-manifest.js +2 -0
  4. package/evento-handler-manifest.js.map +1 -1
  5. package/index.d.ts +1 -0
  6. package/index.js +1 -0
  7. package/index.js.map +1 -1
  8. package/intern/agent-assembly.d.ts +1 -0
  9. package/intern/agent-assembly.js +6 -1
  10. package/intern/agent-assembly.js.map +1 -1
  11. package/intern/agent-belt.d.ts +4 -1
  12. package/intern/agent-belt.js +13 -3
  13. package/intern/agent-belt.js.map +1 -1
  14. package/intern/agent-build-tools.d.ts +4 -0
  15. package/intern/agent-build-tools.js +6 -0
  16. package/intern/agent-build-tools.js.map +1 -1
  17. package/intern/agent-dispatcher.d.ts +4 -0
  18. package/intern/agent-dispatcher.js +13 -5
  19. package/intern/agent-dispatcher.js.map +1 -1
  20. package/intern/agent-evidence.d.ts +12 -0
  21. package/intern/agent-evidence.js +70 -0
  22. package/intern/agent-evidence.js.map +1 -0
  23. package/intern/agent-file-tools.d.ts +12 -0
  24. package/intern/agent-file-tools.js +162 -0
  25. package/intern/agent-file-tools.js.map +1 -0
  26. package/intern/agent-file-validation.d.ts +9 -0
  27. package/intern/agent-file-validation.js +81 -0
  28. package/intern/agent-file-validation.js.map +1 -0
  29. package/intern/agent-instruction.d.ts +1 -1
  30. package/intern/agent-instruction.js +6 -1
  31. package/intern/agent-instruction.js.map +1 -1
  32. package/intern/agent-lane-flag.d.ts +14 -0
  33. package/intern/agent-lane-flag.js +6 -0
  34. package/intern/agent-lane-flag.js.map +1 -1
  35. package/intern/agent-session-instruction.d.ts +1 -0
  36. package/intern/agent-session-instruction.js +43 -0
  37. package/intern/agent-session-instruction.js.map +1 -0
  38. package/intern/agent-session-runtime.d.ts +39 -0
  39. package/intern/agent-session-runtime.js +247 -0
  40. package/intern/agent-session-runtime.js.map +1 -0
  41. package/intern/agent-session-store.d.ts +6 -0
  42. package/intern/agent-session-store.js +52 -0
  43. package/intern/agent-session-store.js.map +1 -0
  44. package/intern/agent-session.d.ts +193 -0
  45. package/intern/agent-session.js +180 -0
  46. package/intern/agent-session.js.map +1 -0
  47. package/intern/agent-turn.d.ts +6 -1
  48. package/intern/agent-turn.js +9 -4
  49. package/intern/agent-turn.js.map +1 -1
  50. package/intern/agent-wake.d.ts +11 -6
  51. package/intern/agent-wake.js +11 -7
  52. package/intern/agent-wake.js.map +1 -1
  53. package/intern/llm-tool-loop.d.ts +22 -1
  54. package/intern/llm-tool-loop.js +130 -7
  55. package/intern/llm-tool-loop.js.map +1 -1
  56. package/intern/mint-fire-core.js +3 -3
  57. package/intern/mint-fire-core.js.map +1 -1
  58. package/intern/open-turn-store.d.ts +6 -0
  59. package/intern/open-turn-store.js +16 -3
  60. package/intern/open-turn-store.js.map +1 -1
  61. package/intern/process-access-bindings.d.ts +1 -0
  62. package/intern/process-access-bindings.js +1 -1
  63. package/intern/process-access-bindings.js.map +1 -1
  64. package/intern/prompt-dispatch-context.d.ts +4 -0
  65. package/intern/prompt-dispatch-context.js +19 -0
  66. package/intern/prompt-dispatch-context.js.map +1 -0
  67. package/intern/turn-terminal.d.ts +61 -0
  68. package/intern/turn-terminal.js +0 -0
  69. package/intern/turn-terminal.js.map +1 -0
  70. package/intern/work-tools.d.ts +1 -0
  71. package/intern/work-tools.js +1 -1
  72. package/intern/work-tools.js.map +1 -1
  73. package/package.json +12 -11
  74. package/public/fork-app.js +24 -26
  75. package/public/fork-app.js.map +1 -1
  76. package/public/fs-prompt.d.ts +2 -1
  77. package/public/fs-prompt.js +57 -2
  78. package/public/fs-prompt.js.map +1 -1
  79. package/public/llm-dispatch.d.ts +2 -2
  80. package/public/llm-dispatch.js +26 -1
  81. package/public/llm-dispatch.js.map +1 -1
  82. package/public/open-chat.d.ts +2 -2
  83. package/public/open-chat.js +25 -0
  84. package/public/open-chat.js.map +1 -1
  85. package/public/prompt-chat-section.js +371 -12
  86. package/public/prompt-chat-section.js.map +1 -1
  87. package/public/report-top-vibes-by-traffic.d.ts +5 -0
  88. package/public/report-top-vibes-by-traffic.js +69 -0
  89. package/public/report-top-vibes-by-traffic.js.map +1 -0
  90. package/public/vibe-traffic-source.d.ts +114 -0
  91. package/public/vibe-traffic-source.js +322 -0
  92. package/public/vibe-traffic-source.js.map +1 -0
  93. package/types.d.ts +5 -0
  94. package/types.js.map +1 -1
  95. package/usage-report/codegen-delivery-alert.js +2 -2
  96. package/usage-report/codegen-delivery-alert.js.map +1 -1
  97. package/usage-report/vibe-traffic-alert-util.d.ts +74 -0
  98. package/usage-report/vibe-traffic-alert-util.js +237 -0
  99. package/usage-report/vibe-traffic-alert-util.js.map +1 -0
  100. package/usage-report/vibe-traffic-alert.d.ts +2 -0
  101. package/usage-report/vibe-traffic-alert.js +99 -0
  102. package/usage-report/vibe-traffic-alert.js.map +1 -0
@@ -0,0 +1,180 @@
1
+ import { Result, exception2Result } from "@adviser/cement";
2
+ import { LLMMessage } from "@vibes.diy/call-ai-v2";
3
+ import { type } from "arktype";
4
+ import { agentFileChange } from "@vibes.diy/api-types";
5
+ const sessionInput = type({ id: "string", messages: LLMMessage.array() });
6
+ const sessionHandle = type({
7
+ id: "string",
8
+ state: "'queued' | 'dispatching' | 'running' | 'settled'",
9
+ "promptId?": "string",
10
+ "input?": "unknown",
11
+ "result?": "string",
12
+ "deadlineAt?": "number",
13
+ "kind?": "'commit'",
14
+ "resultHandleId?": "string",
15
+ });
16
+ export const agentSessionSnapshot = type({
17
+ version: "1",
18
+ status: "'running' | 'idle'",
19
+ messages: LLMMessage.array(),
20
+ inbox: sessionInput.array(),
21
+ handles: sessionHandle.array(),
22
+ acceptedIds: "string[]",
23
+ "draft?": agentFileChange.array(),
24
+ "activePromptId?": "string",
25
+ });
26
+ export const AGENT_SESSION_IDLE = "agent-session-idle";
27
+ export function createAgentSession(args) {
28
+ let state = args.snapshot ?? {
29
+ version: 1,
30
+ status: "running",
31
+ messages: [],
32
+ inbox: [],
33
+ handles: [],
34
+ acceptedIds: [],
35
+ };
36
+ let serial = Promise.resolve(Result.Ok());
37
+ let notify;
38
+ let stopped = false;
39
+ let accepting = true;
40
+ let failure;
41
+ let takenInputs = new Set();
42
+ let takenHandles = new Set();
43
+ function update(change, admit) {
44
+ const operation = serial.then(async () => {
45
+ if (failure !== undefined)
46
+ return Result.Err(failure);
47
+ if (admit !== undefined && admit() === false)
48
+ return Result.Err(AGENT_SESSION_IDLE);
49
+ const next = change(state);
50
+ const saved = await exception2Result(() => args.save(next));
51
+ if (saved.isErr())
52
+ return Result.Err(saved.Err());
53
+ state = next;
54
+ notify?.();
55
+ return Result.Ok();
56
+ });
57
+ serial = operation;
58
+ return operation;
59
+ }
60
+ return {
61
+ messages: () => [...state.messages],
62
+ snapshot: () => structuredClone(state),
63
+ takenResults: () => structuredClone(state.handles.filter((handle) => takenHandles.has(handle.id))),
64
+ stage(change) {
65
+ return update((previous) => ({
66
+ ...previous,
67
+ draft: [...(previous.draft ?? []).filter((file) => file.path !== change.path), change],
68
+ }));
69
+ },
70
+ queueDraft(id) {
71
+ return update((previous) => ({
72
+ ...previous,
73
+ draft: [],
74
+ handles: [...previous.handles, { id, kind: "commit", state: "queued", input: { changes: previous.draft ?? [] } }],
75
+ }));
76
+ },
77
+ deliver(input) {
78
+ return update((previous) => previous.acceptedIds.includes(input.id)
79
+ ? previous
80
+ : {
81
+ ...previous,
82
+ status: "running",
83
+ inbox: [...previous.inbox, input],
84
+ acceptedIds: [...previous.acceptedIds, input.id],
85
+ }, () => accepting && stopped === false);
86
+ },
87
+ register(handle) {
88
+ return update((previous) => ({
89
+ ...previous,
90
+ status: "running",
91
+ handles: [...previous.handles.filter((entry) => entry.id !== handle.id), handle],
92
+ }));
93
+ },
94
+ settle(id, result, resultHandleId) {
95
+ return update((previous) => ({
96
+ ...previous,
97
+ handles: previous.handles.map((handle) => handle.id === id
98
+ ? { ...handle, state: "settled", result, ...(resultHandleId === undefined ? {} : { resultHandleId }) }
99
+ : handle),
100
+ }));
101
+ },
102
+ async checkpoint(messages) {
103
+ const inputs = takenInputs;
104
+ const handles = takenHandles;
105
+ const saved = await update((previous) => ({
106
+ ...previous,
107
+ messages: [...messages],
108
+ inbox: previous.inbox.filter((input) => inputs.has(input.id) === false),
109
+ handles: previous.handles.filter((handle) => handles.has(handle.id) === false),
110
+ }));
111
+ if (saved.isOk()) {
112
+ takenInputs = new Set();
113
+ takenHandles = new Set();
114
+ }
115
+ return saved;
116
+ },
117
+ async next() {
118
+ while (stopped === false) {
119
+ let wake;
120
+ const changed = new Promise((resolve) => {
121
+ wake = resolve;
122
+ });
123
+ notify = wake;
124
+ const saved = await serial;
125
+ if (failure !== undefined)
126
+ return Result.Err(failure);
127
+ if (saved.isErr())
128
+ return Result.Err(saved.Err());
129
+ const ready = state.handles.filter((handle) => handle.state === "settled");
130
+ if (state.inbox.length > 0 || ready.length > 0) {
131
+ takenInputs = new Set(state.inbox.map((input) => input.id));
132
+ takenHandles = new Set(ready.map((handle) => handle.id));
133
+ notify = undefined;
134
+ return Result.Ok([
135
+ ...state.inbox.flatMap((input) => input.messages),
136
+ ...ready.map((handle) => ({
137
+ role: "user",
138
+ content: [{ type: "text", text: handle.result ?? "[tool result] No result was recorded." }],
139
+ })),
140
+ ]);
141
+ }
142
+ if (state.handles.length > 0) {
143
+ await changed;
144
+ continue;
145
+ }
146
+ let timer;
147
+ const idle = new Promise((resolve) => {
148
+ timer = setTimeout(() => resolve("idle"), args.idleMs);
149
+ });
150
+ const winner = await Promise.race([changed, idle]);
151
+ if (timer !== undefined)
152
+ clearTimeout(timer);
153
+ if (winner !== "idle")
154
+ continue;
155
+ const result = await update((previous) => {
156
+ if (previous.inbox.length > 0 || previous.handles.length > 0)
157
+ return previous;
158
+ accepting = false;
159
+ return { ...previous, status: "idle" };
160
+ });
161
+ if (result.isErr())
162
+ return Result.Err(result.Err());
163
+ if (state.status === "idle")
164
+ return Result.Ok(undefined);
165
+ }
166
+ return failure === undefined ? Result.Ok(undefined) : Result.Err(failure);
167
+ },
168
+ fail(error) {
169
+ failure = error;
170
+ stopped = true;
171
+ accepting = false;
172
+ notify?.();
173
+ },
174
+ stop() {
175
+ stopped = true;
176
+ notify?.();
177
+ },
178
+ };
179
+ }
180
+ //# sourceMappingURL=agent-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-session.js","sourceRoot":"","sources":["../../jsr/intern/agent-session.ts"],"names":[],"mappings":"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"}
@@ -3,11 +3,13 @@ import type { LLMRequest, SseStreamMsg } from "@vibes.diy/call-ai-v2";
3
3
  import { VibesApiSQLCtx } from "../types.js";
4
4
  import type { AgentActor } from "./agent-actor.js";
5
5
  import { type AgentBelt, type AgentBeltArgs } from "./agent-belt.js";
6
- import { type LlmToolLoopBudget } from "./llm-tool-loop.js";
6
+ import { createLlmToolLoopStream, type LlmToolLoopBudget, type LlmToolLoopPending } from "./llm-tool-loop.js";
7
7
  export declare const AGENT_TOTAL_BUDGET_MS = 900000;
8
8
  export declare function agentTotalBudgetMs(vctx: VibesApiSQLCtx): number;
9
9
  export declare const AGENT_MAX_TOOL_ROUNDS = 6;
10
10
  export declare const AGENT_MAX_TOOL_CALLS = 16;
11
+ export declare const AGENT_SESSION_MAX_TOOL_ROUNDS = 32;
12
+ export declare const AGENT_SESSION_MAX_TOOL_CALLS = 96;
11
13
  export declare const AGENT_MAX_PROVIDER_ATTEMPTS: number;
12
14
  export interface AgentTurnDispatch {
13
15
  readonly chatId: string;
@@ -33,6 +35,9 @@ export interface AgentTurnStreamArgs {
33
35
  readonly abort?: AbortController;
34
36
  }>>;
35
37
  readonly onDispatch?: (dispatched: AgentTurnDispatch) => void;
38
+ readonly pending?: LlmToolLoopPending;
39
+ readonly session?: Parameters<typeof createLlmToolLoopStream>[0]["session"];
40
+ readonly onToolEvidence?: Parameters<typeof createLlmToolLoopStream>[0]["onToolEvidence"];
36
41
  readonly onError?: (error: string) => void;
37
42
  readonly now?: () => number;
38
43
  }
@@ -1,6 +1,6 @@
1
1
  import { Result } from "@adviser/cement";
2
2
  import { createAgentBelt } from "./agent-belt.js";
3
- import { createLlmToolLoopBudget, createLlmToolLoopStream } from "./llm-tool-loop.js";
3
+ import { createLlmToolLoopBudget, createLlmToolLoopStream, } from "./llm-tool-loop.js";
4
4
  import { AGENT_TURN_CEILING_MS } from "./codegen-build-lock.js";
5
5
  export const AGENT_TOTAL_BUDGET_MS = AGENT_TURN_CEILING_MS;
6
6
  export function agentTotalBudgetMs(vctx) {
@@ -14,6 +14,8 @@ export function agentTotalBudgetMs(vctx) {
14
14
  }
15
15
  export const AGENT_MAX_TOOL_ROUNDS = 6;
16
16
  export const AGENT_MAX_TOOL_CALLS = 16;
17
+ export const AGENT_SESSION_MAX_TOOL_ROUNDS = 32;
18
+ export const AGENT_SESSION_MAX_TOOL_CALLS = 96;
17
19
  export const AGENT_MAX_PROVIDER_ATTEMPTS = AGENT_MAX_TOOL_ROUNDS + 1;
18
20
  export function createAgentTurnStream(args) {
19
21
  const belt = args.belt ??
@@ -27,7 +29,7 @@ export function createAgentTurnStream(args) {
27
29
  });
28
30
  const budget = createLlmToolLoopBudget({
29
31
  totalBudgetMs: agentTotalBudgetMs(args.vctx),
30
- maxAttempts: AGENT_MAX_PROVIDER_ATTEMPTS,
32
+ maxAttempts: args.session === undefined ? AGENT_MAX_PROVIDER_ATTEMPTS : AGENT_SESSION_MAX_TOOL_ROUNDS + 1,
31
33
  ...(args.now === undefined ? {} : { now: args.now }),
32
34
  });
33
35
  budget.attemptsUsed = 1;
@@ -37,8 +39,11 @@ export function createAgentTurnStream(args) {
37
39
  abort: args.abort,
38
40
  budget,
39
41
  execute: belt.executor,
40
- maxToolRounds: AGENT_MAX_TOOL_ROUNDS,
41
- maxToolCalls: AGENT_MAX_TOOL_CALLS,
42
+ ...(args.onToolEvidence === undefined ? {} : { onToolEvidence: args.onToolEvidence }),
43
+ maxToolRounds: args.session === undefined ? AGENT_MAX_TOOL_ROUNDS : AGENT_SESSION_MAX_TOOL_ROUNDS,
44
+ maxToolCalls: args.session === undefined ? AGENT_MAX_TOOL_CALLS : AGENT_SESSION_MAX_TOOL_CALLS,
45
+ ...(args.pending === undefined ? {} : { pending: args.pending }),
46
+ ...(args.session === undefined ? {} : { session: args.session }),
42
47
  dispatch: async (input) => {
43
48
  const r = await args.dispatch({ request: input.request, budget: input.budget });
44
49
  if (r.isErr())
@@ -1 +1 @@
1
- {"version":3,"file":"agent-turn.js","sourceRoot":"","sources":["../../jsr/intern/agent-turn.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-turn.js","sourceRoot":"","sources":["../../jsr/intern/agent-turn.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { DashAuthType } from "@vibes.diy/identity";
2
+ import type { MsgBase, ReqPromptChatSection } from "@vibes.diy/api-types";
2
3
  import { VibesApiSQLCtx } from "../types.js";
3
- import type { AgentDispatchHandle, AgentDispatchHostCtx } from "./agent-dispatcher.js";
4
+ import type { AgentDispatchHostCtx } from "./agent-dispatcher.js";
4
5
  export declare const AGENT_WAKE_MAX_BUDGET = 1;
5
6
  export type AgentWakeSkip = "flag-off" | "not-agent-dispatched" | "not-a-build" | "budget-spent";
6
7
  export type AgentWakeDecision = {
@@ -22,15 +23,19 @@ export interface AgentWakeOutcome {
22
23
  readonly outcome: "applied" | "no-code" | "error";
23
24
  readonly touchedPaths?: readonly string[];
24
25
  }
25
- export declare function renderAgentWakeNote(outcome: AgentWakeOutcome): string;
26
- export interface FireAgentWakeArgs {
26
+ export declare function renderBuildSettledSentence(outcome: AgentWakeOutcome): string;
27
+ export declare function renderAgentWakeNote(outcome: AgentWakeOutcome, session?: boolean): string;
28
+ export interface FireAgentWakeArgs<Host extends AgentDispatchHostCtx> {
27
29
  readonly vctx: VibesApiSQLCtx;
28
- readonly host: AgentDispatchHostCtx;
30
+ readonly host: Host;
29
31
  readonly auth: DashAuthType;
30
32
  readonly outerTid: string;
31
33
  readonly chatId: string;
32
34
  readonly note: string;
33
35
  readonly budget: number;
34
- readonly handle: AgentDispatchHandle;
36
+ readonly handle: (ctx: Omit<Host, "validated" | "enRequest"> & {
37
+ readonly validated: MsgBase<ReqPromptChatSection>;
38
+ readonly enRequest: MsgBase<ReqPromptChatSection>;
39
+ }) => Promise<unknown>;
35
40
  }
36
- export declare function fireAgentWakeTurn(args: FireAgentWakeArgs): void;
41
+ export declare function fireAgentWakeTurn<Host extends AgentDispatchHostCtx>(args: FireAgentWakeArgs<Host>): void;
@@ -17,16 +17,20 @@ export function readAgentWakeBudget(raw) {
17
17
  return AGENT_WAKE_MAX_BUDGET;
18
18
  return Math.max(0, Math.min(AGENT_WAKE_MAX_BUDGET, Math.floor(raw)));
19
19
  }
20
- export function renderAgentWakeNote(outcome) {
20
+ export function renderBuildSettledSentence(outcome) {
21
21
  const touched = outcome.touchedPaths ?? [];
22
- const settled = outcome.outcome === "error"
23
- ? "The build you dispatched did not finish — it failed."
24
- : outcome.outcome === "no-code"
25
- ? "The build you dispatched finished and made no changes to the app."
26
- : `The build you dispatched finished and its changes are saved${touched.length === 0 ? "" : ` (${touched.join(", ")})`}.`;
22
+ if (outcome.outcome === "error")
23
+ return "The build you dispatched did not finish — it failed.";
24
+ if (outcome.outcome === "no-code")
25
+ return "The build you dispatched finished and made no changes to the app.";
26
+ return `The build you dispatched finished and its changes are saved${touched.length === 0 ? "" : ` (${touched.join(", ")})`}.`;
27
+ }
28
+ export function renderAgentWakeNote(outcome, session = false) {
29
+ if (session === true)
30
+ return `[build result] ${renderBuildSettledSentence(outcome)} Continue from this result in the same conversation.`;
27
31
  return [
28
32
  "<build-finished>",
29
- settled,
33
+ renderBuildSettledSentence(outcome),
30
34
  "The app is free for another change now.",
31
35
  "",
32
36
  "This is the platform telling you, not the person: they have not said anything new, so do not answer them",
@@ -1 +1 @@
1
- {"version":3,"file":"agent-wake.js","sourceRoot":"","sources":["../../jsr/intern/agent-wake.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-wake.js","sourceRoot":"","sources":["../../jsr/intern/agent-wake.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,11 @@
1
1
  import { Result } from "@adviser/cement";
2
- import { type LLMRequest, type SseStreamMsg } from "@vibes.diy/call-ai-v2";
2
+ import { type LLMMessage, type LLMRequest, type SseStreamMsg } from "@vibes.diy/call-ai-v2";
3
3
  export declare const MAX_TOOL_RESULT_CHARS = 8192;
4
4
  export declare const MAX_TOOL_CALL_ID_CHARS = 256;
5
5
  export declare const MAX_TOOL_CALL_NAME_CHARS = 256;
6
6
  export declare const MAX_TOOL_CALL_ARGUMENT_CHARS: number;
7
7
  export declare const MAX_PROVIDER_CHUNK_ERRORS = 3;
8
+ export declare const LANDING_ROUND_RESERVE_MS = 5000;
8
9
  export type LlmToolCallField = "id" | "name" | "arguments";
9
10
  export declare class LlmToolLoopError extends Error {
10
11
  readonly field: LlmToolCallField;
@@ -54,6 +55,11 @@ export interface LlmToolLoopDispatchInput {
54
55
  readonly round: number;
55
56
  }
56
57
  export interface LlmToolLoopArgs {
58
+ readonly session?: {
59
+ checkpoint(messages: readonly LLMMessage[]): Promise<Result<void>>;
60
+ next(): Promise<Result<LLMMessage[] | undefined>>;
61
+ readonly dispatchBudgetMs: number;
62
+ };
57
63
  readonly request: LLMRequest;
58
64
  readonly stream: ReadableStream<SseStreamMsg>;
59
65
  readonly abort?: AbortController;
@@ -70,10 +76,25 @@ export interface LlmToolLoopArgs {
70
76
  readonly round: number;
71
77
  readonly calls: readonly LlmToolCall[];
72
78
  }) => void;
79
+ readonly onToolEvidence?: (event: {
80
+ readonly kind: "call" | "receipt";
81
+ readonly call: LlmToolCall;
82
+ readonly text: string;
83
+ }) => Promise<Result<void>>;
84
+ readonly pending?: LlmToolLoopPending;
73
85
  readonly maxToolRounds?: number;
74
86
  readonly maxToolCalls?: number;
75
87
  readonly now?: () => number;
76
88
  }
89
+ export interface LlmToolLoopPending {
90
+ hasPending(): boolean;
91
+ waitForAny(input: {
92
+ readonly remainingMs: number;
93
+ }): Promise<string | undefined>;
94
+ cancelAll(): void;
95
+ markDelivered(): void;
96
+ close(): void;
97
+ }
77
98
  export interface LlmToolLoopResult {
78
99
  readonly request: LLMRequest;
79
100
  readonly rounds: number;
@@ -7,6 +7,7 @@ export const MAX_TOOL_CALL_ID_CHARS = 256;
7
7
  export const MAX_TOOL_CALL_NAME_CHARS = 256;
8
8
  export const MAX_TOOL_CALL_ARGUMENT_CHARS = 64 * 1024;
9
9
  export const MAX_PROVIDER_CHUNK_ERRORS = 3;
10
+ export const LANDING_ROUND_RESERVE_MS = 5_000;
10
11
  export class LlmToolLoopError extends Error {
11
12
  field;
12
13
  limit;
@@ -291,6 +292,10 @@ async function consumeProviderStream(args, stream, request, now, textState) {
291
292
  }
292
293
  if (isSseEnd(event, event.streamId)) {
293
294
  if (sawToolCall === false) {
295
+ if (args.session !== undefined || args.pending?.hasPending() === true) {
296
+ completedNormally = true;
297
+ return Result.Ok({ toolCalls: [], sawToolCall: false, assistantContent, withheldEnd: event });
298
+ }
294
299
  const rVisible = await args.onVisible(event);
295
300
  if (rVisible.isErr())
296
301
  return Result.Err(String(rVisible.Err()));
@@ -324,16 +329,17 @@ export async function runLlmToolLoop(args) {
324
329
  let currentAbort = args.abort;
325
330
  let rounds = 0;
326
331
  let calls = 0;
332
+ let budget = args.budget;
327
333
  const textState = { lastChar: "", separatorOwed: false };
328
334
  try {
329
- if (currentRequest.tools === undefined || currentRequest.tools.length === 0) {
335
+ if ((currentRequest.tools === undefined || currentRequest.tools.length === 0) && args.session === undefined) {
330
336
  const rInitial = await consumeProviderStream({ ...args, abort: currentAbort }, currentStream, currentRequest, now, textState);
331
337
  if (rInitial.isErr())
332
338
  return Result.Err(String(rInitial.Err()));
333
339
  return Result.Ok({ request: currentRequest, rounds, calls });
334
340
  }
335
341
  while (true) {
336
- const rStream = await consumeProviderStream({ ...args, abort: currentAbort }, currentStream, currentRequest, now, textState);
342
+ const rStream = await consumeProviderStream({ ...args, budget, abort: currentAbort }, currentStream, currentRequest, now, textState);
337
343
  if (rStream.isErr()) {
338
344
  const error = rStream.Err();
339
345
  if (error instanceof LlmToolLoopAbandonedError &&
@@ -344,8 +350,91 @@ export async function runLlmToolLoop(args) {
344
350
  return Result.Err(error);
345
351
  }
346
352
  const streamResult = rStream.Ok();
347
- if (streamResult.sawToolCall === false)
353
+ if (streamResult.sawToolCall === false) {
354
+ if (args.session !== undefined && streamResult.withheldEnd !== undefined) {
355
+ const spoken = streamResult.assistantContent === null || streamResult.assistantContent.length === 0
356
+ ? []
357
+ : [{ role: "assistant", content: [{ type: "text", text: streamResult.assistantContent }] }];
358
+ currentRequest = { ...currentRequest, messages: [...currentRequest.messages, ...spoken] };
359
+ const saved = await args.session.checkpoint(currentRequest.messages);
360
+ if (saved.isErr())
361
+ return Result.Err(saved.Err());
362
+ const event = await args.session.next();
363
+ if (event.isErr())
364
+ return Result.Err(event.Err());
365
+ const messages = event.Ok();
366
+ if (messages === undefined) {
367
+ const visible = await args.onVisible(streamResult.withheldEnd);
368
+ if (visible.isErr())
369
+ return Result.Err(visible.Err());
370
+ return Result.Ok({ request: currentRequest, rounds, calls });
371
+ }
372
+ currentRequest = { ...currentRequest, messages: [...currentRequest.messages, ...messages] };
373
+ const checkpoint = await args.session.checkpoint(currentRequest.messages);
374
+ if (checkpoint.isErr())
375
+ return Result.Err(checkpoint.Err());
376
+ budget = createLlmToolLoopBudget({
377
+ totalBudgetMs: args.session.dispatchBudgetMs,
378
+ maxAttempts: args.budget.maxAttempts,
379
+ now,
380
+ });
381
+ rounds = 0;
382
+ calls = 0;
383
+ const dispatched = await args.dispatch({ request: currentRequest, budget, round: rounds });
384
+ if (dispatched.isErr())
385
+ return Result.Err(dispatched.Err());
386
+ currentRequest = dispatched.Ok().request;
387
+ currentStream = dispatched.Ok().stream;
388
+ currentAbort = dispatched.Ok().abort;
389
+ if (textState.lastChar !== "" && /\s/.test(textState.lastChar) === false)
390
+ textState.separatorOwed = true;
391
+ continue;
392
+ }
393
+ const withheld = streamResult.withheldEnd;
394
+ if (withheld !== undefined) {
395
+ const pending = args.pending;
396
+ const waitMs = remainingBudget(args.budget, now) - LANDING_ROUND_RESERVE_MS;
397
+ if (rounds >= maxToolRounds || waitMs <= 0) {
398
+ pending?.close();
399
+ pending?.cancelAll();
400
+ const rVisible = await args.onVisible(withheld);
401
+ if (rVisible.isErr())
402
+ return Result.Err(String(rVisible.Err()));
403
+ return Result.Ok({ request: currentRequest, rounds, calls });
404
+ }
405
+ const landing = await pending?.waitForAny({ remainingMs: waitMs });
406
+ if (landing === undefined) {
407
+ const rVisible = await args.onVisible(withheld);
408
+ if (rVisible.isErr())
409
+ return Result.Err(String(rVisible.Err()));
410
+ return Result.Ok({ request: currentRequest, rounds, calls });
411
+ }
412
+ rounds++;
413
+ if (textState.lastChar !== "" && /\s/.test(textState.lastChar) === false)
414
+ textState.separatorOwed = true;
415
+ const spoken = streamResult.assistantContent === null || streamResult.assistantContent.length === 0
416
+ ? []
417
+ : [{ role: "assistant", content: [{ type: "text", text: streamResult.assistantContent }] }];
418
+ const withLanding = {
419
+ ...currentRequest,
420
+ messages: [...currentRequest.messages, ...spoken, { role: "user", content: [{ type: "text", text: landing }] }],
421
+ };
422
+ const rLanded = await args.dispatch({ request: withLanding, budget: args.budget, round: rounds });
423
+ if (rLanded.isErr()) {
424
+ const rVisible = await args.onVisible(withheld);
425
+ if (rVisible.isErr())
426
+ return Result.Err(String(rVisible.Err()));
427
+ return Result.Err(String(rLanded.Err()));
428
+ }
429
+ pending?.markDelivered();
430
+ const landed = rLanded.Ok();
431
+ currentRequest = landed.request;
432
+ currentStream = landed.stream;
433
+ currentAbort = landed.abort;
434
+ continue;
435
+ }
348
436
  return Result.Ok({ request: currentRequest, rounds, calls });
437
+ }
349
438
  if (rounds >= maxToolRounds)
350
439
  return Result.Err(`LLM tool loop exceeded ${maxToolRounds} rounds`);
351
440
  if (calls + streamResult.toolCalls.length > maxToolCalls) {
@@ -365,17 +454,49 @@ export async function runLlmToolLoop(args) {
365
454
  function: { name: call.name, arguments: call.arguments },
366
455
  })),
367
456
  });
457
+ if (args.session !== undefined) {
458
+ const checkpoint = await args.session.checkpoint([
459
+ ...nextMessages,
460
+ ...streamResult.toolCalls.map((call) => ({
461
+ role: "tool",
462
+ tool_call_id: call.id,
463
+ content: JSON.stringify({
464
+ ok: false,
465
+ error: "Execution interrupted: outcome unknown. Inspect the app and pending build results before deciding whether another change is needed; do not repeat this call automatically.",
466
+ }),
467
+ })),
468
+ ]);
469
+ if (checkpoint.isErr())
470
+ return Result.Err(checkpoint.Err());
471
+ }
368
472
  for (const call of streamResult.toolCalls) {
369
- const rTool = await executeWithDeadline(args.execute, call, args.budget, now, currentAbort?.signal);
473
+ const announced = await args.onToolEvidence?.({ kind: "call", call, text: call.arguments });
474
+ if (announced?.isErr())
475
+ return Result.Err(announced.Err());
476
+ const rTool = await executeWithDeadline(args.execute, call, budget, now, currentAbort?.signal);
370
477
  if (currentAbort?.signal.aborted)
371
478
  return Result.Err("LLM tool loop aborted by parent request");
372
- nextMessages.push({ role: "tool", tool_call_id: call.id, content: toolResultContent(rTool) });
479
+ const content = toolResultContent(rTool);
480
+ const recorded = await args.onToolEvidence?.({ kind: "receipt", call, text: content });
481
+ if (recorded?.isErr())
482
+ return Result.Err(recorded.Err());
483
+ nextMessages.push({ role: "tool", tool_call_id: call.id, content });
373
484
  calls++;
374
485
  }
375
- if (remainingBudget(args.budget, now) <= 0)
486
+ if (remainingBudget(budget, now) <= 0)
376
487
  return Result.Err("LLM tool loop deadline exceeded before resumed dispatch");
377
488
  const nextRequest = { ...currentRequest, messages: nextMessages };
378
- const rDispatch = await args.dispatch({ request: nextRequest, budget: args.budget, round: rounds });
489
+ if (args.session !== undefined) {
490
+ const checkpoint = await args.session.checkpoint(nextMessages);
491
+ if (checkpoint.isErr())
492
+ return Result.Err(checkpoint.Err());
493
+ budget = createLlmToolLoopBudget({
494
+ totalBudgetMs: args.session.dispatchBudgetMs,
495
+ maxAttempts: args.budget.maxAttempts,
496
+ now,
497
+ });
498
+ }
499
+ const rDispatch = await args.dispatch({ request: nextRequest, budget, round: rounds });
379
500
  if (rDispatch.isErr())
380
501
  return Result.Err(String(rDispatch.Err()));
381
502
  const dispatch = rDispatch.Ok();
@@ -385,6 +506,8 @@ export async function runLlmToolLoop(args) {
385
506
  }
386
507
  }
387
508
  finally {
509
+ args.pending?.close();
510
+ args.pending?.cancelAll();
388
511
  args.onSpend?.({ rounds, calls });
389
512
  }
390
513
  }