@hachej/boring-agent 0.1.23 → 0.1.24
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/{agentPluginEvents-zyIvVjsA.d.ts → agentPluginEvents-CF0BGY4D.d.ts} +11 -1
- package/dist/{chunk-6R7O6BHW.js → chunk-FILARC5X.js} +6 -28
- package/dist/chunk-HDOSWEXG.js +29 -0
- package/dist/eval/index.js +33 -1
- package/dist/front/index.d.ts +49 -4
- package/dist/front/index.js +432 -76
- package/dist/front/styles.css +8 -0
- package/dist/{harness-BCit36Ha.d.ts → harness-CQ0uw6xW.d.ts} +5 -0
- package/dist/server/index.d.ts +23 -6
- package/dist/server/index.js +971 -615
- package/dist/shared/index.d.ts +17 -17
- package/dist/shared/index.js +8 -6
- package/docs/ERROR_CODES.md +4 -0
- package/docs/README.md +1 -0
- package/docs/runtime.md +133 -2
- package/package.json +9 -8
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
interface WorkspaceRuntimeContext {
|
|
2
|
+
/** Agent-visible working directory shared by file-tree and shell execution. */
|
|
3
|
+
readonly runtimeCwd: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
1
6
|
interface Workspace {
|
|
7
|
+
/** Agent-visible workspace root; must match runtimeContext.runtimeCwd. */
|
|
2
8
|
readonly root: string;
|
|
9
|
+
readonly runtimeContext: WorkspaceRuntimeContext;
|
|
3
10
|
readFile(relPath: string): Promise<string>;
|
|
4
11
|
/** Optional binary read operation for media/document previews. */
|
|
5
12
|
readBinaryFile?(relPath: string): Promise<Uint8Array>;
|
|
@@ -137,6 +144,8 @@ interface Sandbox {
|
|
|
137
144
|
readonly provider: string;
|
|
138
145
|
/** Capabilities this sandbox advertises (used for tool gating). */
|
|
139
146
|
readonly capabilities: readonly SandboxCapability[];
|
|
147
|
+
/** Agent-visible runtime cwd; must match the paired Workspace root. */
|
|
148
|
+
readonly runtimeContext: WorkspaceRuntimeContext;
|
|
140
149
|
/**
|
|
141
150
|
* Optional initialization hook. Some backends bind to a workspace +
|
|
142
151
|
* session at construction (Vercel: snapshot warm-up; Bwrap: bind
|
|
@@ -171,6 +180,7 @@ interface Sandbox {
|
|
|
171
180
|
dispose?(): Promise<void>;
|
|
172
181
|
}
|
|
173
182
|
interface ExecOptions {
|
|
183
|
+
/** Runtime-visible cwd. Relative paths resolve from `runtimeContext.runtimeCwd`. */
|
|
174
184
|
cwd?: string;
|
|
175
185
|
env?: Record<string, string>;
|
|
176
186
|
signal?: AbortSignal;
|
|
@@ -287,4 +297,4 @@ interface PluginRestartWarning {
|
|
|
287
297
|
message: string;
|
|
288
298
|
}
|
|
289
299
|
|
|
290
|
-
export { type Entry as E, type FileSearch as F, type IsolatedCodeInput as I, type PluginRestartWarning as P, type Sandbox as S, type Workspace as W, type ExecOptions as a, type ExecResult as b, type IsolatedCodeOutput as c, type SandboxCapability as d, type SandboxHandleRecord as e, type SandboxHandleStore as f, type Stat as g, WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT as h };
|
|
300
|
+
export { type Entry as E, type FileSearch as F, type IsolatedCodeInput as I, type PluginRestartWarning as P, type Sandbox as S, type Workspace as W, type ExecOptions as a, type ExecResult as b, type IsolatedCodeOutput as c, type SandboxCapability as d, type SandboxHandleRecord as e, type SandboxHandleStore as f, type Stat as g, WORKSPACE_AGENT_PLUGINS_RELOADED_EVENT as h, type WorkspaceRuntimeContext as i };
|
|
@@ -1,16 +1,3 @@
|
|
|
1
|
-
// src/shared/telemetry.ts
|
|
2
|
-
var noopTelemetry = {
|
|
3
|
-
capture() {
|
|
4
|
-
}
|
|
5
|
-
};
|
|
6
|
-
function safeCapture(telemetry, event) {
|
|
7
|
-
try {
|
|
8
|
-
void Promise.resolve(telemetry.capture(event)).catch(() => {
|
|
9
|
-
});
|
|
10
|
-
} catch {
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
1
|
// src/shared/error-codes.ts
|
|
15
2
|
import { z } from "zod";
|
|
16
3
|
var ErrorCode = z.enum([
|
|
@@ -28,6 +15,11 @@ var ErrorCode = z.enum([
|
|
|
28
15
|
"PATH_NOT_FOUND",
|
|
29
16
|
"PATH_NOT_WRITABLE",
|
|
30
17
|
"WORKSPACE_UNINITIALIZED",
|
|
18
|
+
"WORKSPACE_NOT_READY",
|
|
19
|
+
// Agent runtime / provisioning
|
|
20
|
+
"AGENT_RUNTIME_NOT_READY",
|
|
21
|
+
"RUNTIME_PROVISIONING_FAILED",
|
|
22
|
+
"RUNTIME_PROVISIONING_LOCKED",
|
|
31
23
|
// Sandbox / exec
|
|
32
24
|
"BWRAP_UNAVAILABLE",
|
|
33
25
|
"BWRAP_TIMEOUT",
|
|
@@ -78,24 +70,10 @@ var ErrorLogFieldsSchema = z.object({
|
|
|
78
70
|
msg: z.string().min(1)
|
|
79
71
|
}).catchall(z.unknown());
|
|
80
72
|
|
|
81
|
-
// src/shared/validateTool.ts
|
|
82
|
-
function validateTool(tool) {
|
|
83
|
-
if (typeof tool !== "object" || tool === null) return null;
|
|
84
|
-
const t = tool;
|
|
85
|
-
if (typeof t.name !== "string" || t.name.length === 0) return null;
|
|
86
|
-
if (typeof t.description !== "string") return null;
|
|
87
|
-
if (typeof t.parameters !== "object" || t.parameters === null) return null;
|
|
88
|
-
if (typeof t.execute !== "function") return null;
|
|
89
|
-
return t;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
73
|
export {
|
|
93
|
-
noopTelemetry,
|
|
94
|
-
safeCapture,
|
|
95
74
|
ErrorCode,
|
|
96
75
|
ERROR_CODES,
|
|
97
76
|
ApiErrorPayloadSchema,
|
|
98
77
|
ApiErrorResponseSchema,
|
|
99
|
-
ErrorLogFieldsSchema
|
|
100
|
-
validateTool
|
|
78
|
+
ErrorLogFieldsSchema
|
|
101
79
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/shared/telemetry.ts
|
|
2
|
+
var noopTelemetry = {
|
|
3
|
+
capture() {
|
|
4
|
+
}
|
|
5
|
+
};
|
|
6
|
+
function safeCapture(telemetry, event) {
|
|
7
|
+
try {
|
|
8
|
+
void Promise.resolve(telemetry.capture(event)).catch(() => {
|
|
9
|
+
});
|
|
10
|
+
} catch {
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/shared/validateTool.ts
|
|
15
|
+
function validateTool(tool) {
|
|
16
|
+
if (typeof tool !== "object" || tool === null) return null;
|
|
17
|
+
const t = tool;
|
|
18
|
+
if (typeof t.name !== "string" || t.name.length === 0) return null;
|
|
19
|
+
if (typeof t.description !== "string") return null;
|
|
20
|
+
if (typeof t.parameters !== "object" || t.parameters === null) return null;
|
|
21
|
+
if (typeof t.execute !== "function") return null;
|
|
22
|
+
return t;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
noopTelemetry,
|
|
27
|
+
safeCapture,
|
|
28
|
+
validateTool
|
|
29
|
+
};
|
package/dist/eval/index.js
CHANGED
|
@@ -219,6 +219,18 @@ async function evalAgentPrompt(opts) {
|
|
|
219
219
|
if (attempts > maxRetries) return lastResult;
|
|
220
220
|
continue;
|
|
221
221
|
}
|
|
222
|
+
if (captured.errorText) {
|
|
223
|
+
lastResult = {
|
|
224
|
+
ok: false,
|
|
225
|
+
actual: captured.toolCalls,
|
|
226
|
+
text: captured.text,
|
|
227
|
+
usage: captured.usage,
|
|
228
|
+
attempts,
|
|
229
|
+
reason: `stream: ${captured.errorText}`
|
|
230
|
+
};
|
|
231
|
+
if (attempts > maxRetries) return lastResult;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
222
234
|
const matchResult = matchExpectations(opts, captured.toolCalls);
|
|
223
235
|
lastResult = {
|
|
224
236
|
ok: matchResult.ok,
|
|
@@ -307,6 +319,7 @@ ${opts.prompt}` : opts.prompt;
|
|
|
307
319
|
function parseSseStream(body) {
|
|
308
320
|
const toolCalls = [];
|
|
309
321
|
const textParts = [];
|
|
322
|
+
const errorParts = [];
|
|
310
323
|
let usage;
|
|
311
324
|
for (const line of body.split("\n")) {
|
|
312
325
|
const trimmed = line.trim();
|
|
@@ -337,9 +350,28 @@ function parseSseStream(body) {
|
|
|
337
350
|
usage = { input: obj.input, output: obj.output };
|
|
338
351
|
}
|
|
339
352
|
}
|
|
353
|
+
} else if (type === "error") {
|
|
354
|
+
const text = stringifyStreamError(chunk);
|
|
355
|
+
if (text) errorParts.push(text);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
toolCalls,
|
|
360
|
+
text: textParts.join(""),
|
|
361
|
+
usage,
|
|
362
|
+
errorText: errorParts.length ? errorParts.join("\n") : void 0
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function stringifyStreamError(chunk) {
|
|
366
|
+
for (const key of ["errorText", "message", "error"]) {
|
|
367
|
+
const value = chunk[key];
|
|
368
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
369
|
+
if (value && typeof value === "object") {
|
|
370
|
+
const message = value.message;
|
|
371
|
+
if (typeof message === "string" && message.trim()) return message;
|
|
340
372
|
}
|
|
341
373
|
}
|
|
342
|
-
return
|
|
374
|
+
return "unknown stream error";
|
|
343
375
|
}
|
|
344
376
|
function withTimeout(p, ms, label) {
|
|
345
377
|
return new Promise((resolve, reject) => {
|
package/dist/front/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as ai from 'ai';
|
|
3
|
+
import { FileUIPart, UIMessage, ChatStatus } from 'ai';
|
|
2
4
|
import * as react from 'react';
|
|
3
5
|
import { ReactNode, ComponentType, HTMLAttributes, ComponentProps, FormEvent } from 'react';
|
|
4
6
|
import { T as ToolUiMetadata } from '../tool-ui-DIFNGwYd.js';
|
|
5
|
-
import * as ai from 'ai';
|
|
6
|
-
import { UIMessage, FileUIPart, ChatStatus } from 'ai';
|
|
7
7
|
import * as _ai_sdk_react from '@ai-sdk/react';
|
|
8
|
-
import { S as SendMessageInput, e as SessionSummary } from '../harness-
|
|
8
|
+
import { S as SendMessageInput, e as SessionSummary } from '../harness-CQ0uw6xW.js';
|
|
9
9
|
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger, InputGroupAddon, InputGroupButton, InputGroupTextarea } from '@hachej/boring-ui-kit';
|
|
10
10
|
import { Streamdown } from 'streamdown';
|
|
11
11
|
import { StickToBottom } from 'use-stick-to-bottom';
|
|
@@ -165,6 +165,23 @@ type ComposerBlocker = {
|
|
|
165
165
|
sessionId?: string;
|
|
166
166
|
actions?: ComposerBlockerAction[];
|
|
167
167
|
};
|
|
168
|
+
type ChatPanelWorkspaceWarmupStatus = {
|
|
169
|
+
status: 'preparing';
|
|
170
|
+
requirement?: 'workspace-fs' | 'sandbox-exec' | 'ui-bridge';
|
|
171
|
+
message?: string;
|
|
172
|
+
} | {
|
|
173
|
+
status: 'ready';
|
|
174
|
+
} | {
|
|
175
|
+
status: 'failed';
|
|
176
|
+
requirement?: 'workspace-fs' | 'sandbox-exec' | 'ui-bridge';
|
|
177
|
+
message?: string;
|
|
178
|
+
};
|
|
179
|
+
type ChatSubmitSource = 'composer' | 'suggestion';
|
|
180
|
+
interface ChatSubmitContext {
|
|
181
|
+
files: FileUIPart[];
|
|
182
|
+
sessionId: string;
|
|
183
|
+
source: ChatSubmitSource;
|
|
184
|
+
}
|
|
168
185
|
interface ChatPanelProps {
|
|
169
186
|
sessionId: string;
|
|
170
187
|
toolRenderers?: ToolRendererOverrides;
|
|
@@ -222,6 +239,8 @@ interface ChatPanelProps {
|
|
|
222
239
|
onData?: (part: unknown) => void;
|
|
223
240
|
/** Headers sent with chat and chat-history requests. */
|
|
224
241
|
requestHeaders?: Record<string, string>;
|
|
242
|
+
/** When false, skip initial chat history/stream resume requests until the user sends. */
|
|
243
|
+
hydrateMessages?: boolean;
|
|
225
244
|
/**
|
|
226
245
|
* Called with a file path when the user clicks the path label inside
|
|
227
246
|
* a read / write / edit tool card. Hosts (e.g. @hachej/boring-workspace)
|
|
@@ -237,6 +256,29 @@ interface ChatPanelProps {
|
|
|
237
256
|
* is zero-cost when off.
|
|
238
257
|
*/
|
|
239
258
|
debug?: boolean;
|
|
259
|
+
/** Draft text restored into the composer on mount/update. */
|
|
260
|
+
initialDraft?: string;
|
|
261
|
+
/** Auto-submit initialDraft once after it is restored. Defaults to false. */
|
|
262
|
+
autoSubmitInitialDraft?: boolean;
|
|
263
|
+
/** Called after initialDraft is applied to the composer. */
|
|
264
|
+
onDraftRestored?: () => void;
|
|
265
|
+
/** Called after an auto-submitted initial draft is accepted for sending. */
|
|
266
|
+
onAutoSubmitInitialDraftAccepted?: () => void;
|
|
267
|
+
/** Called after an auto-submitted initial draft finishes its turn. */
|
|
268
|
+
onAutoSubmitInitialDraftSettled?: () => void;
|
|
269
|
+
/**
|
|
270
|
+
* Runs before any agent/model/session-history network send. Return false to
|
|
271
|
+
* cancel submission and keep the draft in the composer.
|
|
272
|
+
*/
|
|
273
|
+
onBeforeSubmit?: (draft: string, ctx: ChatSubmitContext) => false | void | Promise<false | void>;
|
|
274
|
+
/** Disable server-backed model/skill discovery for public/local-only shells. */
|
|
275
|
+
serverResourcesEnabled?: boolean;
|
|
276
|
+
/** Center the empty-state prompt/composer for public landing experiences. */
|
|
277
|
+
emptyPlacement?: 'default' | 'hero';
|
|
278
|
+
/** Placeholder shown in the composer textarea. */
|
|
279
|
+
composerPlaceholder?: string;
|
|
280
|
+
/** Current workspace warmup state. Preparing/failed states keep submits local so drafts are not lost. */
|
|
281
|
+
workspaceWarmupStatus?: ChatPanelWorkspaceWarmupStatus;
|
|
240
282
|
/** Generic host-provided blockers that prevent starting a new user turn. */
|
|
241
283
|
composerBlockers?: ComposerBlocker[];
|
|
242
284
|
/** Called when the user presses Stop in the composer. */
|
|
@@ -276,12 +318,15 @@ type UseAgentChatOptions = Pick<SendMessageInput, 'sessionId' | 'model' | 'think
|
|
|
276
318
|
onData?: (part: unknown) => void;
|
|
277
319
|
requestHeaders?: Record<string, string>;
|
|
278
320
|
persistMessages?: boolean;
|
|
321
|
+
hydrateMessages?: boolean;
|
|
279
322
|
};
|
|
280
323
|
declare function useAgentChat(opts: UseAgentChatOptions): _ai_sdk_react.UseChatHelpers<UIMessage<unknown, ai.UIDataTypes, ai.UITools>>;
|
|
281
324
|
|
|
282
325
|
interface UseSessionsOptions {
|
|
283
326
|
requestHeaders?: Record<string, string>;
|
|
284
327
|
storageKey?: string;
|
|
328
|
+
enabled?: boolean;
|
|
329
|
+
refreshKey?: unknown;
|
|
285
330
|
}
|
|
286
331
|
interface UseSessionsResult {
|
|
287
332
|
sessions: SessionSummary[];
|
|
@@ -384,7 +429,7 @@ type PromptInputProps = Omit<HTMLAttributes<HTMLFormElement>, "onSubmit" | "onEr
|
|
|
384
429
|
code: "max_files" | "max_file_size" | "accept";
|
|
385
430
|
message: string;
|
|
386
431
|
}) => void;
|
|
387
|
-
onSubmit: (message: PromptInputMessage, event: FormEvent<HTMLFormElement>) => void | Promise<void>;
|
|
432
|
+
onSubmit: (message: PromptInputMessage, event: FormEvent<HTMLFormElement>) => false | void | Promise<false | void>;
|
|
388
433
|
/** When provided, files are uploaded to the server immediately on add and the
|
|
389
434
|
* attachment URL is replaced with the stable server path before submit. */
|
|
390
435
|
onUploadFile?: (file: File) => Promise<{
|