@hachej/boring-agent 0.1.9 → 0.1.12
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/dist/front/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { ReactNode, ComponentType, HTMLAttributes, ComponentProps, FormEvent, El
|
|
|
4
4
|
import * as ai from 'ai';
|
|
5
5
|
import { UIMessage, FileUIPart, ChatStatus } from 'ai';
|
|
6
6
|
import * as _ai_sdk_react from '@ai-sdk/react';
|
|
7
|
-
import { S as SendMessageInput, d as SessionSummary } from '../harness-
|
|
7
|
+
import { S as SendMessageInput, d as SessionSummary } from '../harness-DT3ZzdAN.js';
|
|
8
8
|
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger, InputGroupButton, TooltipContent, InputGroupAddon, InputGroupTextarea } from '@hachej/boring-ui-kit';
|
|
9
9
|
import { Streamdown } from 'streamdown';
|
|
10
10
|
import { StickToBottom } from 'use-stick-to-bottom';
|
package/dist/front/index.js
CHANGED
|
@@ -344,32 +344,61 @@ function useAgentChat(opts) {
|
|
|
344
344
|
|
|
345
345
|
// src/front/splitFollowUp.ts
|
|
346
346
|
function splitFollowUp(msgs, consumed, genId) {
|
|
347
|
-
|
|
347
|
+
let targetIdx = msgs.findIndex(
|
|
348
348
|
(m) => m.role === "assistant" && m.parts?.some((p) => {
|
|
349
349
|
const part = p;
|
|
350
350
|
return part.type === "data-followup-consumed" || part.id?.startsWith("turn-");
|
|
351
351
|
})
|
|
352
352
|
);
|
|
353
|
+
if (targetIdx < 0) {
|
|
354
|
+
for (let i = msgs.length - 1; i >= 0; i--) {
|
|
355
|
+
if (msgs[i]?.role === "assistant") {
|
|
356
|
+
targetIdx = i;
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const displayTextFromMarker = msgs.flatMap((m) => m.parts ?? []).map((p) => p).find((p) => p.type === "data-followup-consumed" && typeof p.data?.text === "string")?.data?.text;
|
|
353
362
|
const userMsg = {
|
|
354
363
|
id: genId(),
|
|
355
364
|
role: "user",
|
|
356
|
-
parts: [...consumed.files, { type: "text", text: consumed.text }]
|
|
365
|
+
parts: [...consumed.files, { type: "text", text: displayTextFromMarker ?? consumed.text }]
|
|
357
366
|
};
|
|
358
367
|
if (targetIdx < 0) {
|
|
359
368
|
return [...msgs, userMsg];
|
|
360
369
|
}
|
|
361
370
|
const target = msgs[targetIdx];
|
|
362
|
-
const
|
|
371
|
+
const parts = target.parts ?? [];
|
|
372
|
+
let markerIdx = parts.findIndex((p) => {
|
|
363
373
|
const part = p;
|
|
364
374
|
return part.type === "data-followup-consumed" || part.id?.startsWith("turn-");
|
|
365
|
-
})
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
375
|
+
});
|
|
376
|
+
let markerIsPart = markerIdx >= 0 && parts[markerIdx].type === "data-followup-consumed";
|
|
377
|
+
if (markerIdx < 0) {
|
|
378
|
+
const textPartIndexes = parts.map((p, index) => p.type === "text" ? index : -1).filter((index) => index >= 0);
|
|
379
|
+
if (textPartIndexes.length > 1) {
|
|
380
|
+
markerIdx = textPartIndexes[textPartIndexes.length - 1];
|
|
381
|
+
markerIsPart = false;
|
|
382
|
+
} else {
|
|
383
|
+
return [...msgs.slice(0, targetIdx), userMsg, target, ...msgs.slice(targetIdx + 1)];
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
const turn1Parts = markerIdx >= 0 ? parts.slice(0, markerIdx) : parts;
|
|
387
|
+
const turn2Parts = markerIdx >= 0 ? parts.slice(markerIsPart ? markerIdx + 1 : markerIdx) : [];
|
|
369
388
|
const asst1 = { ...target, parts: turn1Parts };
|
|
370
389
|
const asst2 = { ...target, id: genId(), parts: turn2Parts };
|
|
371
390
|
return [...msgs.slice(0, targetIdx), asst1, userMsg, asst2, ...msgs.slice(targetIdx + 1)];
|
|
372
391
|
}
|
|
392
|
+
function splitFollowUpForDisplay(msgs, consumed, pending, ids) {
|
|
393
|
+
const draft = consumed ?? pending;
|
|
394
|
+
if (!draft || !ids) return msgs;
|
|
395
|
+
const hasFollowUpBoundary = msgs.some(
|
|
396
|
+
(m) => m.role === "assistant" && (m.parts?.some((p) => p.id?.startsWith("turn-") || p.type === "data-followup-consumed") || (m.parts?.filter((p) => p.type === "text").length ?? 0) > 1)
|
|
397
|
+
);
|
|
398
|
+
if (!hasFollowUpBoundary) return msgs;
|
|
399
|
+
let n = 0;
|
|
400
|
+
return splitFollowUp(msgs, draft, () => n++ === 0 ? ids.userId : ids.assistantId);
|
|
401
|
+
}
|
|
373
402
|
|
|
374
403
|
// src/front/DebugDrawer.tsx
|
|
375
404
|
import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef5, useState as useState4 } from "react";
|
|
@@ -3778,6 +3807,8 @@ function ChatPanel(props) {
|
|
|
3778
3807
|
const [debugWidth, setDebugWidth] = useState13(440);
|
|
3779
3808
|
const [pendingMessage, setPendingMessage] = useState13(null);
|
|
3780
3809
|
const pendingMessageRef = useRef10(null);
|
|
3810
|
+
const followUpPostedRef = useRef10(false);
|
|
3811
|
+
const followUpPostTimerRef = useRef10(null);
|
|
3781
3812
|
const consumedFollowUpRef = useRef10(null);
|
|
3782
3813
|
const followUpSplitIdsRef = useRef10(null);
|
|
3783
3814
|
const {
|
|
@@ -3793,7 +3824,8 @@ function ChatPanel(props) {
|
|
|
3793
3824
|
onData: (part) => {
|
|
3794
3825
|
if (part?.type === "data-followup-consumed") {
|
|
3795
3826
|
const pending = pendingMessageRef.current;
|
|
3796
|
-
|
|
3827
|
+
const serverText = part?.data?.text;
|
|
3828
|
+
consumedFollowUpRef.current = pending ? { text: pending.text, files: pending.files } : typeof serverText === "string" ? { text: serverText, files: [] } : null;
|
|
3797
3829
|
followUpSplitIdsRef.current = {
|
|
3798
3830
|
userId: globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-followup-user`,
|
|
3799
3831
|
assistantId: globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-followup-assistant`
|
|
@@ -3923,17 +3955,35 @@ function ChatPanel(props) {
|
|
|
3923
3955
|
return () => globalThis.removeEventListener?.("boring:model-change", onChange);
|
|
3924
3956
|
}, []);
|
|
3925
3957
|
const isStreaming = status === "submitted" || status === "streaming";
|
|
3926
|
-
const displayMessages = useMemo10(
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
)
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3958
|
+
const displayMessages = useMemo10(
|
|
3959
|
+
() => splitFollowUpForDisplay(
|
|
3960
|
+
messages,
|
|
3961
|
+
consumedFollowUpRef.current,
|
|
3962
|
+
pendingMessageRef.current,
|
|
3963
|
+
followUpSplitIdsRef.current
|
|
3964
|
+
),
|
|
3965
|
+
[messages]
|
|
3966
|
+
);
|
|
3967
|
+
const postPendingFollowUp = useCallback12((pending) => {
|
|
3968
|
+
if (followUpPostedRef.current) return;
|
|
3969
|
+
followUpPostedRef.current = true;
|
|
3970
|
+
fetch(`/api/v1/agent/chat/${encodeURIComponent(sessionId)}/followup`, {
|
|
3971
|
+
method: "POST",
|
|
3972
|
+
headers: {
|
|
3973
|
+
"Content-Type": "application/json",
|
|
3974
|
+
...requestHeaders
|
|
3975
|
+
},
|
|
3976
|
+
body: JSON.stringify({ message: pending.serverMessage, displayText: pending.text, attachments: pending.attachments })
|
|
3977
|
+
}).catch(() => {
|
|
3978
|
+
followUpPostedRef.current = false;
|
|
3979
|
+
});
|
|
3980
|
+
}, [sessionId, requestHeaders]);
|
|
3981
|
+
useEffect11(() => {
|
|
3982
|
+
if (status !== "streaming") return;
|
|
3983
|
+
const pending = pendingMessageRef.current;
|
|
3984
|
+
if (!pending) return;
|
|
3985
|
+
postPendingFollowUp(pending);
|
|
3986
|
+
}, [status, postPendingFollowUp]);
|
|
3937
3987
|
const prevStatusForQueue = useRef10(status);
|
|
3938
3988
|
useEffect11(() => {
|
|
3939
3989
|
const prev = prevStatusForQueue.current;
|
|
@@ -3946,6 +3996,9 @@ function ChatPanel(props) {
|
|
|
3946
3996
|
consumedFollowUpRef.current = null;
|
|
3947
3997
|
followUpSplitIdsRef.current = null;
|
|
3948
3998
|
pendingMessageRef.current = null;
|
|
3999
|
+
followUpPostedRef.current = false;
|
|
4000
|
+
if (followUpPostTimerRef.current) clearTimeout(followUpPostTimerRef.current);
|
|
4001
|
+
followUpPostTimerRef.current = null;
|
|
3949
4002
|
setPendingMessage(null);
|
|
3950
4003
|
let n = 0;
|
|
3951
4004
|
const genId = () => ids ? n++ === 0 ? ids.userId : ids.assistantId : globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
|
|
@@ -3966,6 +4019,9 @@ function ChatPanel(props) {
|
|
|
3966
4019
|
consumedFollowUpRef.current = null;
|
|
3967
4020
|
followUpSplitIdsRef.current = null;
|
|
3968
4021
|
pendingMessageRef.current = null;
|
|
4022
|
+
followUpPostedRef.current = false;
|
|
4023
|
+
if (followUpPostTimerRef.current) clearTimeout(followUpPostTimerRef.current);
|
|
4024
|
+
followUpPostTimerRef.current = null;
|
|
3969
4025
|
setPendingMessage(null);
|
|
3970
4026
|
fetch(`/api/v1/agent/chat/${encodeURIComponent(sessionId)}/followup`, {
|
|
3971
4027
|
method: "DELETE",
|
|
@@ -4155,16 +4211,17 @@ ${content}
|
|
|
4155
4211
|
attachments: resolvedAttachments
|
|
4156
4212
|
};
|
|
4157
4213
|
pendingMessageRef.current = nextPending;
|
|
4214
|
+
followUpPostedRef.current = false;
|
|
4158
4215
|
setPendingMessage(nextPending);
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
}
|
|
4216
|
+
if (status === "streaming") {
|
|
4217
|
+
postPendingFollowUp(nextPending);
|
|
4218
|
+
} else {
|
|
4219
|
+
if (followUpPostTimerRef.current) clearTimeout(followUpPostTimerRef.current);
|
|
4220
|
+
followUpPostTimerRef.current = setTimeout(() => {
|
|
4221
|
+
const pending = pendingMessageRef.current;
|
|
4222
|
+
if (pending) postPendingFollowUp(pending);
|
|
4223
|
+
}, 1e3);
|
|
4224
|
+
}
|
|
4168
4225
|
}
|
|
4169
4226
|
return;
|
|
4170
4227
|
}
|
|
@@ -51,7 +51,7 @@ interface AgentHarness {
|
|
|
51
51
|
* A `data-followup-consumed` chunk is emitted before the follow-up turn so
|
|
52
52
|
* the client can clear its pending-message bubble immediately.
|
|
53
53
|
*/
|
|
54
|
-
followUp?(sessionId: string, text: string, attachments?: MessageAttachment[]): void
|
|
54
|
+
followUp?(sessionId: string, text: string, attachments?: MessageAttachment[], displayText?: string): void | Promise<void>;
|
|
55
55
|
/**
|
|
56
56
|
* Discard any queued follow-up for this session (called by the Stop button).
|
|
57
57
|
*/
|
package/dist/server/index.js
CHANGED
|
@@ -2242,13 +2242,25 @@ function timeoutResult(durationMs) {
|
|
|
2242
2242
|
stderrEncoding: "utf-8"
|
|
2243
2243
|
};
|
|
2244
2244
|
}
|
|
2245
|
+
function toRemotePath(value) {
|
|
2246
|
+
if (value === VERCEL_SANDBOX_WORKSPACE_ROOT) return VERCEL_SANDBOX_REMOTE_ROOT;
|
|
2247
|
+
if (value.startsWith(`${VERCEL_SANDBOX_WORKSPACE_ROOT}/`)) {
|
|
2248
|
+
return `${VERCEL_SANDBOX_REMOTE_ROOT}${value.slice(VERCEL_SANDBOX_WORKSPACE_ROOT.length)}`;
|
|
2249
|
+
}
|
|
2250
|
+
return value;
|
|
2251
|
+
}
|
|
2245
2252
|
function toRemoteCwd(cwd) {
|
|
2246
2253
|
if (!cwd) return cwd;
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2254
|
+
return toRemotePath(cwd);
|
|
2255
|
+
}
|
|
2256
|
+
function toRemoteCommand(command) {
|
|
2257
|
+
return command.replaceAll(VERCEL_SANDBOX_WORKSPACE_ROOT, VERCEL_SANDBOX_REMOTE_ROOT);
|
|
2258
|
+
}
|
|
2259
|
+
function toRemoteEnv(env) {
|
|
2260
|
+
if (!env) return void 0;
|
|
2261
|
+
return Object.fromEntries(
|
|
2262
|
+
Object.entries(env).map(([key, value]) => [key, toRemotePath(value)])
|
|
2263
|
+
);
|
|
2252
2264
|
}
|
|
2253
2265
|
function createVercelSandboxExec(sandbox, execOpts = {}) {
|
|
2254
2266
|
return {
|
|
@@ -2294,9 +2306,9 @@ function createVercelSandboxExec(sandbox, execOpts = {}) {
|
|
|
2294
2306
|
}
|
|
2295
2307
|
const result = await sandbox.runCommand({
|
|
2296
2308
|
cmd: "sh",
|
|
2297
|
-
args: ["-c", cmd],
|
|
2309
|
+
args: ["-c", toRemoteCommand(cmd)],
|
|
2298
2310
|
cwd: toRemoteCwd(opts?.cwd),
|
|
2299
|
-
env: opts?.env,
|
|
2311
|
+
env: toRemoteEnv(opts?.env),
|
|
2300
2312
|
signal: controller.signal,
|
|
2301
2313
|
stdout: createStreamWritable(stdoutCollector, captureState, opts?.onStdout),
|
|
2302
2314
|
stderr: createStreamWritable(stderrCollector, captureState, opts?.onStderr)
|
|
@@ -3689,6 +3701,16 @@ function mergePiPackageSources(base = [], additional = []) {
|
|
|
3689
3701
|
}
|
|
3690
3702
|
|
|
3691
3703
|
// src/server/harness/pi-coding-agent/createHarness.ts
|
|
3704
|
+
function extractUserMessageText(message) {
|
|
3705
|
+
const record = message;
|
|
3706
|
+
if (record?.role !== "user") return "";
|
|
3707
|
+
if (typeof record.content === "string") return record.content;
|
|
3708
|
+
if (!Array.isArray(record.content)) return "";
|
|
3709
|
+
return record.content.map((part) => {
|
|
3710
|
+
const p = part;
|
|
3711
|
+
return p.type === "text" && typeof p.text === "string" ? p.text : "";
|
|
3712
|
+
}).join("");
|
|
3713
|
+
}
|
|
3692
3714
|
function extractAssistantMessageText(message) {
|
|
3693
3715
|
const record = message;
|
|
3694
3716
|
const role = typeof record?.role === "string" ? record.role : void 0;
|
|
@@ -3874,16 +3896,18 @@ function createPiCodingAgentHarness(opts) {
|
|
|
3874
3896
|
await originalDelete(ctx, sessionId);
|
|
3875
3897
|
disposePiSession(sessionId);
|
|
3876
3898
|
};
|
|
3877
|
-
const
|
|
3899
|
+
const nativeFollowUpPending = /* @__PURE__ */ new Set();
|
|
3878
3900
|
return {
|
|
3879
3901
|
id: "pi-coding-agent",
|
|
3880
3902
|
placement: "server",
|
|
3881
3903
|
sessions: sessionStore,
|
|
3882
|
-
followUp(sessionId, text,
|
|
3883
|
-
|
|
3904
|
+
async followUp(sessionId, text, _attachments, _displayText = text) {
|
|
3905
|
+
const handle = piSessions.get(sessionId);
|
|
3906
|
+
if (!handle) return;
|
|
3907
|
+
nativeFollowUpPending.add(sessionId);
|
|
3908
|
+
await handle.piSession.followUp(text);
|
|
3884
3909
|
},
|
|
3885
|
-
clearFollowUp(
|
|
3886
|
-
harnessFollowUpQueues.delete(sessionId);
|
|
3910
|
+
clearFollowUp(_sessionId) {
|
|
3887
3911
|
},
|
|
3888
3912
|
/**
|
|
3889
3913
|
* Pi exposes the resolved system prompt as a getter on AgentSession.
|
|
@@ -3900,7 +3924,6 @@ function createPiCodingAgentHarness(opts) {
|
|
|
3900
3924
|
input,
|
|
3901
3925
|
ctx
|
|
3902
3926
|
);
|
|
3903
|
-
harnessFollowUpQueues.delete(input.sessionId);
|
|
3904
3927
|
const chunks = [];
|
|
3905
3928
|
let done = false;
|
|
3906
3929
|
let streamError = null;
|
|
@@ -3960,7 +3983,6 @@ function createPiCodingAgentHarness(opts) {
|
|
|
3960
3983
|
return chunk2;
|
|
3961
3984
|
});
|
|
3962
3985
|
}
|
|
3963
|
-
let pendingFollowUp;
|
|
3964
3986
|
let promptSettled = false;
|
|
3965
3987
|
let promptPromise = Promise.resolve();
|
|
3966
3988
|
const unsubscribe = piSession.subscribe((event) => {
|
|
@@ -3982,7 +4004,19 @@ function createPiCodingAgentHarness(opts) {
|
|
|
3982
4004
|
activeTools.delete(event.toolCallId);
|
|
3983
4005
|
if (activeTools.size === 0) stopHeartbeat();
|
|
3984
4006
|
}
|
|
3985
|
-
let converted
|
|
4007
|
+
let converted;
|
|
4008
|
+
if (event.type === "message_start" && event.message?.role === "user") {
|
|
4009
|
+
const text = extractUserMessageText(event.message);
|
|
4010
|
+
converted = text && text !== input.message ? [{ type: "data-followup-consumed", data: { text } }] : [];
|
|
4011
|
+
if (text && text !== input.message) {
|
|
4012
|
+
inlineTurnIndex += 1;
|
|
4013
|
+
nativeFollowUpPending.delete(input.sessionId);
|
|
4014
|
+
}
|
|
4015
|
+
} else if (event.type === "message_end" && event.message?.role === "user") {
|
|
4016
|
+
converted = [];
|
|
4017
|
+
} else {
|
|
4018
|
+
converted = namespaceInlinePartIds(dedupStartChunks(piEventToChunks(event)));
|
|
4019
|
+
}
|
|
3986
4020
|
if (event.type === "message_update") {
|
|
3987
4021
|
const ame = event.assistantMessageEvent;
|
|
3988
4022
|
if (ame.type === "text_end" && typeof ame.content === "string" && ame.content.length > 0 && !textDeltaSeen.has(ame.contentIndex)) {
|
|
@@ -4042,16 +4076,7 @@ function createPiCodingAgentHarness(opts) {
|
|
|
4042
4076
|
assistantText += text;
|
|
4043
4077
|
}
|
|
4044
4078
|
}
|
|
4045
|
-
|
|
4046
|
-
if (followUp !== void 0 && !ctx.abortSignal.aborted) {
|
|
4047
|
-
harnessFollowUpQueues.delete(input.sessionId);
|
|
4048
|
-
chunks.push({ type: "data-followup-consumed" });
|
|
4049
|
-
inlineTurnIndex += 1;
|
|
4050
|
-
sawTextChunk = false;
|
|
4051
|
-
textStartSeen.clear();
|
|
4052
|
-
textDeltaSeen.clear();
|
|
4053
|
-
assistantText = "";
|
|
4054
|
-
pendingFollowUp = followUp;
|
|
4079
|
+
if (nativeFollowUpPending.has(input.sessionId) && !ctx.abortSignal.aborted) {
|
|
4055
4080
|
} else {
|
|
4056
4081
|
done = true;
|
|
4057
4082
|
stopHeartbeat();
|
|
@@ -4107,11 +4132,6 @@ ${attachmentNotes.join("\n")}` : message,
|
|
|
4107
4132
|
const prepared = await prepareTurn(message, attachments);
|
|
4108
4133
|
return piSession.prompt(prepared.message, prepared.promptOpts).then(() => {
|
|
4109
4134
|
promptSettled = true;
|
|
4110
|
-
if (pendingFollowUp !== void 0 && !ctx.abortSignal.aborted) {
|
|
4111
|
-
const next = pendingFollowUp;
|
|
4112
|
-
pendingFollowUp = void 0;
|
|
4113
|
-
promptPromise = startTurn(next.message, next.attachments);
|
|
4114
|
-
}
|
|
4115
4135
|
}).catch((err) => {
|
|
4116
4136
|
promptSettled = true;
|
|
4117
4137
|
streamError = err;
|
|
@@ -4535,12 +4555,25 @@ function boundFs(workspaceRoot) {
|
|
|
4535
4555
|
|
|
4536
4556
|
// src/server/tools/operations/vercel.ts
|
|
4537
4557
|
import { relative as relative5 } from "path";
|
|
4558
|
+
function rootAliases(workspace) {
|
|
4559
|
+
const aliases = [workspace.root];
|
|
4560
|
+
if (workspace.root === VERCEL_SANDBOX_WORKSPACE_ROOT) aliases.push(VERCEL_SANDBOX_REMOTE_ROOT);
|
|
4561
|
+
if (workspace.root === VERCEL_SANDBOX_REMOTE_ROOT) aliases.push(VERCEL_SANDBOX_WORKSPACE_ROOT);
|
|
4562
|
+
return aliases;
|
|
4563
|
+
}
|
|
4538
4564
|
function toRelPath(workspace, absolutePath) {
|
|
4539
|
-
const
|
|
4540
|
-
|
|
4541
|
-
|
|
4565
|
+
for (const root of rootAliases(workspace)) {
|
|
4566
|
+
const rel = relative5(root, absolutePath);
|
|
4567
|
+
if (!rel.startsWith("..") && !rel.startsWith("/")) return rel;
|
|
4568
|
+
}
|
|
4569
|
+
const skillMarker = "/.agents/skills/";
|
|
4570
|
+
const skillIndex = absolutePath.indexOf(skillMarker);
|
|
4571
|
+
if (skillIndex >= 0) {
|
|
4572
|
+
return `.agents/skills/${absolutePath.slice(skillIndex + skillMarker.length)}`;
|
|
4542
4573
|
}
|
|
4543
|
-
|
|
4574
|
+
throw new Error(
|
|
4575
|
+
`path "${absolutePath}" is outside workspace; use a path relative to the workspace root or under ${rootAliases(workspace).join(" / ")}`
|
|
4576
|
+
);
|
|
4544
4577
|
}
|
|
4545
4578
|
function vercelBashOps(sandbox) {
|
|
4546
4579
|
return {
|
|
@@ -4599,6 +4632,39 @@ function vercelEditOps(workspace) {
|
|
|
4599
4632
|
}
|
|
4600
4633
|
};
|
|
4601
4634
|
}
|
|
4635
|
+
function toRemotePath2(value) {
|
|
4636
|
+
if (value === VERCEL_SANDBOX_WORKSPACE_ROOT) return VERCEL_SANDBOX_REMOTE_ROOT;
|
|
4637
|
+
if (value.startsWith(`${VERCEL_SANDBOX_WORKSPACE_ROOT}/`)) {
|
|
4638
|
+
return `${VERCEL_SANDBOX_REMOTE_ROOT}${value.slice(VERCEL_SANDBOX_WORKSPACE_ROOT.length)}`;
|
|
4639
|
+
}
|
|
4640
|
+
return value;
|
|
4641
|
+
}
|
|
4642
|
+
function findPredicate(pattern) {
|
|
4643
|
+
const isPathShaped = pattern.includes("/") || pattern.includes("**");
|
|
4644
|
+
if (!isPathShaped) return `-name ${shellEscape(pattern)}`;
|
|
4645
|
+
let translated = pattern.replaceAll("**", "*").replace(/^\/+/, "");
|
|
4646
|
+
if (!translated.startsWith("*")) translated = `*${translated}`;
|
|
4647
|
+
return `-path ${shellEscape(translated)}`;
|
|
4648
|
+
}
|
|
4649
|
+
function findIgnoreArgs(cwd, ignore) {
|
|
4650
|
+
return ignore.map((pattern) => `! -path ${shellEscape(`${cwd}/${pattern.replace(/^\/+/, "")}/*`)}`).join(" ");
|
|
4651
|
+
}
|
|
4652
|
+
function fallbackFindCommand(pattern, cwd, options) {
|
|
4653
|
+
return [
|
|
4654
|
+
"find",
|
|
4655
|
+
shellEscape(cwd),
|
|
4656
|
+
"-maxdepth 20",
|
|
4657
|
+
"-type f",
|
|
4658
|
+
findIgnoreArgs(cwd, options.ignore),
|
|
4659
|
+
findPredicate(pattern),
|
|
4660
|
+
`| head -n ${Math.max(1, Math.trunc(options.limit))}`
|
|
4661
|
+
].filter(Boolean).join(" ");
|
|
4662
|
+
}
|
|
4663
|
+
function isFdMissing(result) {
|
|
4664
|
+
if (result.exitCode !== 127) return false;
|
|
4665
|
+
const stderr = Buffer.from(result.stderr).toString("utf-8");
|
|
4666
|
+
return /fd: not found|fd: command not found|not found/i.test(stderr);
|
|
4667
|
+
}
|
|
4602
4668
|
function vercelFindOps(sandbox, workspace) {
|
|
4603
4669
|
return {
|
|
4604
4670
|
async exists(absolutePath) {
|
|
@@ -4617,18 +4683,25 @@ function vercelFindOps(sandbox, workspace) {
|
|
|
4617
4683
|
return result.exitCode === 0;
|
|
4618
4684
|
},
|
|
4619
4685
|
async glob(pattern, cwd, options) {
|
|
4686
|
+
const remoteCwd = toRemotePath2(cwd);
|
|
4620
4687
|
const args = ["fd", "--glob", "--no-require-git", "--max-results", String(options.limit)];
|
|
4621
4688
|
for (const ig of options.ignore) {
|
|
4622
4689
|
args.push("--exclude", ig);
|
|
4623
4690
|
}
|
|
4624
|
-
args.push(pattern,
|
|
4625
|
-
|
|
4691
|
+
args.push(pattern, remoteCwd);
|
|
4692
|
+
let result = await sandbox.exec(args.map(shellEscape).join(" "), {
|
|
4626
4693
|
timeoutMs: 3e4,
|
|
4627
4694
|
maxOutputBytes: 1048576
|
|
4628
4695
|
});
|
|
4696
|
+
if (isFdMissing(result)) {
|
|
4697
|
+
result = await sandbox.exec(fallbackFindCommand(pattern, remoteCwd, options), {
|
|
4698
|
+
timeoutMs: 3e4,
|
|
4699
|
+
maxOutputBytes: 1048576
|
|
4700
|
+
});
|
|
4701
|
+
}
|
|
4629
4702
|
if (result.exitCode !== 0 && result.exitCode !== 1) {
|
|
4630
4703
|
const stderr = Buffer.from(result.stderr).toString("utf-8").trim();
|
|
4631
|
-
throw new Error(`
|
|
4704
|
+
throw new Error(`file search failed (exit ${result.exitCode}): ${stderr}`);
|
|
4632
4705
|
}
|
|
4633
4706
|
const stdout = Buffer.from(result.stdout).toString("utf-8");
|
|
4634
4707
|
return stdout.split("\n").filter(Boolean);
|
|
@@ -5268,6 +5341,15 @@ function contentTypeForPath(path4) {
|
|
|
5268
5341
|
return "image/svg+xml";
|
|
5269
5342
|
case ".webp":
|
|
5270
5343
|
return "image/webp";
|
|
5344
|
+
case ".css":
|
|
5345
|
+
return "text/css; charset=utf-8";
|
|
5346
|
+
case ".html":
|
|
5347
|
+
case ".htm":
|
|
5348
|
+
return "text/html; charset=utf-8";
|
|
5349
|
+
case ".js":
|
|
5350
|
+
return "text/javascript; charset=utf-8";
|
|
5351
|
+
case ".mjs":
|
|
5352
|
+
return "text/javascript; charset=utf-8";
|
|
5271
5353
|
case ".pdf":
|
|
5272
5354
|
return "application/pdf";
|
|
5273
5355
|
default:
|
|
@@ -6149,7 +6231,12 @@ function chatRoutes(app, opts, done) {
|
|
|
6149
6231
|
});
|
|
6150
6232
|
}
|
|
6151
6233
|
const runtime = await resolveRuntime(request);
|
|
6152
|
-
runtime.harness.followUp?.(
|
|
6234
|
+
await runtime.harness.followUp?.(
|
|
6235
|
+
sessionId,
|
|
6236
|
+
body.message,
|
|
6237
|
+
parsedAttachments.data,
|
|
6238
|
+
typeof body.displayText === "string" && body.displayText.length > 0 ? body.displayText : body.message
|
|
6239
|
+
);
|
|
6153
6240
|
return reply.code(202).send({ queued: true });
|
|
6154
6241
|
}
|
|
6155
6242
|
);
|
|
@@ -6272,9 +6359,16 @@ import { randomUUID as randomUUID4 } from "crypto";
|
|
|
6272
6359
|
import { z as z2 } from "zod";
|
|
6273
6360
|
var DEFAULT_SESSION_TITLE2 = "New session";
|
|
6274
6361
|
var DEFAULT_WORKSPACE_ID2 = "default";
|
|
6362
|
+
var MAX_ANALYSIS_TRANSCRIPT_CHARS = 12e4;
|
|
6275
6363
|
var createSessionBodySchema = z2.object({
|
|
6276
6364
|
title: z2.string().min(1).max(200).optional()
|
|
6277
6365
|
}).optional();
|
|
6366
|
+
var analyzeSessionBodySchema = z2.object({
|
|
6367
|
+
instructions: z2.string().max(4e3).optional(),
|
|
6368
|
+
title: z2.string().min(1).max(200).optional(),
|
|
6369
|
+
run: z2.boolean().optional(),
|
|
6370
|
+
includeTranscript: z2.boolean().optional()
|
|
6371
|
+
}).optional();
|
|
6278
6372
|
var SessionNotFoundError = class extends Error {
|
|
6279
6373
|
constructor(sessionId) {
|
|
6280
6374
|
super(`Session not found: ${sessionId}`);
|
|
@@ -6371,13 +6465,141 @@ function classifySessionError(err, reply) {
|
|
|
6371
6465
|
}
|
|
6372
6466
|
});
|
|
6373
6467
|
}
|
|
6468
|
+
function stableStringify(value) {
|
|
6469
|
+
if (typeof value === "string") return value;
|
|
6470
|
+
try {
|
|
6471
|
+
return JSON.stringify(value, null, 2);
|
|
6472
|
+
} catch {
|
|
6473
|
+
return String(value);
|
|
6474
|
+
}
|
|
6475
|
+
}
|
|
6476
|
+
function partText(part) {
|
|
6477
|
+
const value = part;
|
|
6478
|
+
if (typeof value.text === "string") return value.text;
|
|
6479
|
+
if (typeof value.delta === "string") return value.delta;
|
|
6480
|
+
if (typeof value.content === "string") return value.content;
|
|
6481
|
+
return "";
|
|
6482
|
+
}
|
|
6483
|
+
function toolName(part) {
|
|
6484
|
+
if (typeof part.toolName === "string") return part.toolName;
|
|
6485
|
+
if (typeof part.type === "string" && part.type.startsWith("tool-")) {
|
|
6486
|
+
return part.type.slice("tool-".length);
|
|
6487
|
+
}
|
|
6488
|
+
return "tool";
|
|
6489
|
+
}
|
|
6490
|
+
function formatToolPart(part) {
|
|
6491
|
+
const name = toolName(part);
|
|
6492
|
+
const lines = [`[tool:${name}]`];
|
|
6493
|
+
if ("input" in part) {
|
|
6494
|
+
lines.push("input:", stableStringify(part.input));
|
|
6495
|
+
}
|
|
6496
|
+
if ("output" in part) {
|
|
6497
|
+
lines.push("output:", stableStringify(part.output));
|
|
6498
|
+
}
|
|
6499
|
+
if (typeof part.errorText === "string" && part.errorText.length > 0) {
|
|
6500
|
+
lines.push("error:", part.errorText);
|
|
6501
|
+
}
|
|
6502
|
+
return lines.join("\n");
|
|
6503
|
+
}
|
|
6504
|
+
function formatMessageForTranscript(message, index) {
|
|
6505
|
+
const msg = message;
|
|
6506
|
+
const role = String(msg.role ?? "unknown").toUpperCase();
|
|
6507
|
+
const parts = Array.isArray(msg.parts) ? msg.parts : [];
|
|
6508
|
+
const lines = [`## ${index + 1}. ${role}`];
|
|
6509
|
+
if (typeof msg.content === "string" && msg.content.trim()) {
|
|
6510
|
+
lines.push(msg.content.trim());
|
|
6511
|
+
}
|
|
6512
|
+
for (const part of parts) {
|
|
6513
|
+
const record = part;
|
|
6514
|
+
const type = typeof record.type === "string" ? record.type : "";
|
|
6515
|
+
if (type === "text") {
|
|
6516
|
+
const text2 = partText(record).trim();
|
|
6517
|
+
if (text2) lines.push(text2);
|
|
6518
|
+
continue;
|
|
6519
|
+
}
|
|
6520
|
+
if (type === "reasoning") {
|
|
6521
|
+
const text2 = partText(record).trim();
|
|
6522
|
+
if (text2) lines.push(`[reasoning]
|
|
6523
|
+
${text2}`);
|
|
6524
|
+
continue;
|
|
6525
|
+
}
|
|
6526
|
+
if (type.startsWith("tool-")) {
|
|
6527
|
+
lines.push(formatToolPart(record));
|
|
6528
|
+
continue;
|
|
6529
|
+
}
|
|
6530
|
+
const text = partText(record).trim();
|
|
6531
|
+
if (text) lines.push(`[${type || "part"}]
|
|
6532
|
+
${text}`);
|
|
6533
|
+
}
|
|
6534
|
+
if (lines.length === 1) lines.push("(no visible content)");
|
|
6535
|
+
return lines.join("\n\n");
|
|
6536
|
+
}
|
|
6537
|
+
function formatSessionTranscript(session) {
|
|
6538
|
+
const header = [
|
|
6539
|
+
`# Agent session transcript: ${session.title}`,
|
|
6540
|
+
"",
|
|
6541
|
+
`- Session: ${session.id}`,
|
|
6542
|
+
`- Created: ${session.createdAt}`,
|
|
6543
|
+
`- Updated: ${session.updatedAt}`,
|
|
6544
|
+
`- User turns: ${session.turnCount}`
|
|
6545
|
+
];
|
|
6546
|
+
const body = session.messages.map(formatMessageForTranscript);
|
|
6547
|
+
return [...header, "", ...body].join("\n");
|
|
6548
|
+
}
|
|
6549
|
+
function truncateMiddle(value, maxChars) {
|
|
6550
|
+
if (value.length <= maxChars) return value;
|
|
6551
|
+
const keep = Math.floor((maxChars - 200) / 2);
|
|
6552
|
+
return `${value.slice(0, keep)}
|
|
6553
|
+
|
|
6554
|
+
[... transcript truncated: ${value.length - keep * 2} chars omitted ...]
|
|
6555
|
+
|
|
6556
|
+
${value.slice(-keep)}`;
|
|
6557
|
+
}
|
|
6558
|
+
function buildAnalysisPrompt(session, transcript, instructions) {
|
|
6559
|
+
const boundedTranscript = truncateMiddle(transcript, MAX_ANALYSIS_TRANSCRIPT_CHARS);
|
|
6560
|
+
return [
|
|
6561
|
+
"You are an agent-session analyst. Analyze the transcript below and explain what is going on.",
|
|
6562
|
+
"",
|
|
6563
|
+
"Return a concise, evidence-backed report with these sections:",
|
|
6564
|
+
"1. User goal",
|
|
6565
|
+
"2. Current state",
|
|
6566
|
+
"3. What the agent did",
|
|
6567
|
+
"4. Failures, confusing behavior, or likely root causes",
|
|
6568
|
+
"5. Files/tools/commands that matter",
|
|
6569
|
+
"6. Risks and recommended next actions",
|
|
6570
|
+
"",
|
|
6571
|
+
"Rules:",
|
|
6572
|
+
"- Cite concrete transcript evidence when possible.",
|
|
6573
|
+
'- Say "unknown" when the transcript does not prove something.',
|
|
6574
|
+
"- Do not modify files unless explicitly asked in follow-up.",
|
|
6575
|
+
instructions ? `- Extra user instructions: ${instructions}` : "",
|
|
6576
|
+
"",
|
|
6577
|
+
`Source session: ${session.id} (${session.title})`,
|
|
6578
|
+
"",
|
|
6579
|
+
"<transcript>",
|
|
6580
|
+
boundedTranscript,
|
|
6581
|
+
"</transcript>"
|
|
6582
|
+
].filter(Boolean).join("\n");
|
|
6583
|
+
}
|
|
6584
|
+
function analysisTextFromChunks(chunks) {
|
|
6585
|
+
return chunks.map((chunk2) => {
|
|
6586
|
+
const record = chunk2;
|
|
6587
|
+
return record.type === "text-delta" && typeof record.delta === "string" ? record.delta : "";
|
|
6588
|
+
}).join("").trim();
|
|
6589
|
+
}
|
|
6374
6590
|
function sessionRoutes(app, opts, done) {
|
|
6375
6591
|
const sessionStore = opts.sessionStore ?? new InMemorySessionStore();
|
|
6376
6592
|
const validateCreateBody = createBodyValidator(createSessionBodySchema);
|
|
6593
|
+
const validateAnalyzeBody = createBodyValidator(analyzeSessionBodySchema);
|
|
6377
6594
|
async function resolveSessionStore(request) {
|
|
6378
6595
|
if (opts.getSessionStore) return await opts.getSessionStore(request);
|
|
6379
6596
|
return sessionStore;
|
|
6380
6597
|
}
|
|
6598
|
+
async function resolveRuntime(request) {
|
|
6599
|
+
if (opts.getRuntime) return await opts.getRuntime(request);
|
|
6600
|
+
if (opts.harness && opts.workdir) return { harness: opts.harness, workdir: opts.workdir };
|
|
6601
|
+
throw new Error("session analysis requires harness/workdir or getRuntime");
|
|
6602
|
+
}
|
|
6381
6603
|
app.get("/api/v1/agent/sessions", async (request, reply) => {
|
|
6382
6604
|
try {
|
|
6383
6605
|
const store = await resolveSessionStore(request);
|
|
@@ -6412,6 +6634,113 @@ function sessionRoutes(app, opts, done) {
|
|
|
6412
6634
|
return classifySessionError(err, reply);
|
|
6413
6635
|
}
|
|
6414
6636
|
});
|
|
6637
|
+
app.get("/api/v1/agent/sessions/:id/transcript", async (request, reply) => {
|
|
6638
|
+
const params = request.params;
|
|
6639
|
+
const sessionId = requireSessionId(params.id, reply);
|
|
6640
|
+
if (sessionId === null) return;
|
|
6641
|
+
const query = request.query;
|
|
6642
|
+
const format = query.format === "json" ? "json" : "markdown";
|
|
6643
|
+
try {
|
|
6644
|
+
const store = await resolveSessionStore(request);
|
|
6645
|
+
const session = await store.load(getSessionCtx(request), sessionId);
|
|
6646
|
+
const transcript = formatSessionTranscript(session);
|
|
6647
|
+
if (format === "json") {
|
|
6648
|
+
return {
|
|
6649
|
+
session: {
|
|
6650
|
+
id: session.id,
|
|
6651
|
+
title: session.title,
|
|
6652
|
+
createdAt: session.createdAt,
|
|
6653
|
+
updatedAt: session.updatedAt,
|
|
6654
|
+
turnCount: session.turnCount
|
|
6655
|
+
},
|
|
6656
|
+
transcript,
|
|
6657
|
+
messages: session.messages
|
|
6658
|
+
};
|
|
6659
|
+
}
|
|
6660
|
+
return reply.header("Content-Type", "text/markdown; charset=utf-8").send(transcript);
|
|
6661
|
+
} catch (err) {
|
|
6662
|
+
return classifySessionError(err, reply);
|
|
6663
|
+
}
|
|
6664
|
+
});
|
|
6665
|
+
app.post(
|
|
6666
|
+
"/api/v1/agent/sessions/:id/analysis",
|
|
6667
|
+
{ preHandler: validateAnalyzeBody },
|
|
6668
|
+
async (request, reply) => {
|
|
6669
|
+
const params = request.params;
|
|
6670
|
+
const sourceSessionId = requireSessionId(params.id, reply);
|
|
6671
|
+
if (sourceSessionId === null) return;
|
|
6672
|
+
const body = request.body;
|
|
6673
|
+
const run2 = body?.run === true;
|
|
6674
|
+
const sessionCtx = getSessionCtx(request);
|
|
6675
|
+
try {
|
|
6676
|
+
const store = await resolveSessionStore(request);
|
|
6677
|
+
const sourceSession = await store.load(sessionCtx, sourceSessionId);
|
|
6678
|
+
const transcript = formatSessionTranscript(sourceSession);
|
|
6679
|
+
const prompt = buildAnalysisPrompt(sourceSession, transcript, body?.instructions);
|
|
6680
|
+
let runtime = null;
|
|
6681
|
+
if (run2) {
|
|
6682
|
+
try {
|
|
6683
|
+
runtime = await resolveRuntime(request);
|
|
6684
|
+
} catch {
|
|
6685
|
+
return reply.code(501).send({
|
|
6686
|
+
error: {
|
|
6687
|
+
code: ERROR_CODE_NOT_IMPLEMENTED,
|
|
6688
|
+
message: "session analysis runtime is not configured"
|
|
6689
|
+
}
|
|
6690
|
+
});
|
|
6691
|
+
}
|
|
6692
|
+
}
|
|
6693
|
+
const analysisSession = await store.create(sessionCtx, {
|
|
6694
|
+
title: body?.title ?? `Analysis: ${sourceSession.title}`.slice(0, 200)
|
|
6695
|
+
});
|
|
6696
|
+
if (!run2) {
|
|
6697
|
+
return {
|
|
6698
|
+
sourceSession: {
|
|
6699
|
+
id: sourceSession.id,
|
|
6700
|
+
title: sourceSession.title,
|
|
6701
|
+
createdAt: sourceSession.createdAt,
|
|
6702
|
+
updatedAt: sourceSession.updatedAt,
|
|
6703
|
+
turnCount: sourceSession.turnCount
|
|
6704
|
+
},
|
|
6705
|
+
analysisSession,
|
|
6706
|
+
prompt,
|
|
6707
|
+
transcriptUrl: `/api/v1/agent/sessions/${encodeURIComponent(sourceSession.id)}/transcript`,
|
|
6708
|
+
...body?.includeTranscript ? { transcript } : {}
|
|
6709
|
+
};
|
|
6710
|
+
}
|
|
6711
|
+
if (!runtime) {
|
|
6712
|
+
throw new Error("session analysis runtime is not configured");
|
|
6713
|
+
}
|
|
6714
|
+
const abortController = new AbortController();
|
|
6715
|
+
const chunks = [];
|
|
6716
|
+
for await (const chunk2 of runtime.harness.sendMessage(
|
|
6717
|
+
{ sessionId: analysisSession.id, message: prompt },
|
|
6718
|
+
{
|
|
6719
|
+
abortSignal: abortController.signal,
|
|
6720
|
+
workdir: runtime.workdir
|
|
6721
|
+
}
|
|
6722
|
+
)) {
|
|
6723
|
+
chunks.push(chunk2);
|
|
6724
|
+
}
|
|
6725
|
+
return {
|
|
6726
|
+
sourceSession: {
|
|
6727
|
+
id: sourceSession.id,
|
|
6728
|
+
title: sourceSession.title,
|
|
6729
|
+
createdAt: sourceSession.createdAt,
|
|
6730
|
+
updatedAt: sourceSession.updatedAt,
|
|
6731
|
+
turnCount: sourceSession.turnCount
|
|
6732
|
+
},
|
|
6733
|
+
analysisSession,
|
|
6734
|
+
prompt,
|
|
6735
|
+
transcriptUrl: `/api/v1/agent/sessions/${encodeURIComponent(sourceSession.id)}/transcript`,
|
|
6736
|
+
analysisText: analysisTextFromChunks(chunks),
|
|
6737
|
+
...body?.includeTranscript ? { transcript } : {}
|
|
6738
|
+
};
|
|
6739
|
+
} catch (err) {
|
|
6740
|
+
return classifySessionError(err, reply);
|
|
6741
|
+
}
|
|
6742
|
+
}
|
|
6743
|
+
);
|
|
6415
6744
|
app.delete("/api/v1/agent/sessions/:id", async (request, reply) => {
|
|
6416
6745
|
const params = request.params;
|
|
6417
6746
|
const sessionId = requireSessionId(params.id, reply);
|
|
@@ -6732,7 +7061,9 @@ async function createAgentApp(opts = {}) {
|
|
|
6732
7061
|
sessionChangesTracker
|
|
6733
7062
|
});
|
|
6734
7063
|
await app.register(sessionRoutes, {
|
|
6735
|
-
sessionStore: harness.sessions
|
|
7064
|
+
sessionStore: harness.sessions,
|
|
7065
|
+
harness,
|
|
7066
|
+
workdir: runtimeBundle.workspace.root
|
|
6736
7067
|
});
|
|
6737
7068
|
await app.register(systemPromptRoutes, { harness });
|
|
6738
7069
|
await app.register(modelsRoutes);
|
|
@@ -7184,6 +7515,13 @@ var registerAgentRoutes = async (app, opts) => {
|
|
|
7184
7515
|
getSessionStore: async (request) => {
|
|
7185
7516
|
const binding = await getBindingForRequest(request);
|
|
7186
7517
|
return binding.harness.sessions;
|
|
7518
|
+
},
|
|
7519
|
+
getRuntime: async (request) => {
|
|
7520
|
+
const binding = await getBindingForRequest(request);
|
|
7521
|
+
return {
|
|
7522
|
+
harness: binding.harness,
|
|
7523
|
+
workdir: binding.runtimeBundle.workspace.root
|
|
7524
|
+
};
|
|
7187
7525
|
}
|
|
7188
7526
|
});
|
|
7189
7527
|
await app.register(systemPromptRoutes, {
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AgentHarness, R as RunContext, S as SendMessageInput, a as SessionCtx, b as SessionDetail, c as SessionStore, d as SessionSummary } from '../harness-
|
|
1
|
+
export { A as AgentHarness, R as RunContext, S as SendMessageInput, a as SessionCtx, b as SessionDetail, c as SessionStore, d as SessionSummary } from '../harness-DT3ZzdAN.js';
|
|
2
2
|
import { W as Workspace, S as Sandbox, F as FileSearch, A as AgentTool } from '../sandbox-handle-store-DCNEJJ6b.js';
|
|
3
3
|
export { E as Entry, a as ExecOptions, b as ExecResult, I as IsolatedCodeInput, c as IsolatedCodeOutput, J as JSONSchema, d as SandboxCapability, e as SandboxHandleRecord, f as SandboxHandleStore, g as Stat, T as ToolExecContext, h as ToolResult } from '../sandbox-handle-store-DCNEJJ6b.js';
|
|
4
4
|
export { UIMessage, UIMessageChunk } from 'ai';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hachej/boring-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Pane-embeddable coding agent. Ships direct/local/vercel-sandbox execution modes behind one interface.",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"use-stick-to-bottom": "^1.1.3",
|
|
75
75
|
"yaml": "^2.8.3",
|
|
76
76
|
"zod": "^3.25.76",
|
|
77
|
-
"@hachej/boring-ui-kit": "0.1.
|
|
77
|
+
"@hachej/boring-ui-kit": "0.1.12"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@opentelemetry/api": "^1.9.1",
|