usebeeline 0.0.100 → 0.0.104
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/usebeeline.mjs +218 -83
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -4389,44 +4389,44 @@ async function readUpdateAttempt(layout) {
|
|
|
4389
4389
|
return void 0;
|
|
4390
4390
|
}
|
|
4391
4391
|
}
|
|
4392
|
-
async function writeUpdateAttempt(layout,
|
|
4392
|
+
async function writeUpdateAttempt(layout, record3) {
|
|
4393
4393
|
await mkdir15(join9(layout.releasesRoot, ".state"), { recursive: true });
|
|
4394
4394
|
const path = updateAttemptPath(layout);
|
|
4395
4395
|
const staged = `${path}.${process.pid}.tmp`;
|
|
4396
|
-
await writeFile10(staged, `${JSON.stringify(
|
|
4396
|
+
await writeFile10(staged, `${JSON.stringify(record3, null, 2)}
|
|
4397
4397
|
`, { mode: 384 });
|
|
4398
4398
|
await rename4(staged, path);
|
|
4399
4399
|
}
|
|
4400
|
-
async function replaceUpdateAttempt(layout,
|
|
4401
|
-
await writeUpdateAttempt(layout,
|
|
4400
|
+
async function replaceUpdateAttempt(layout, record3) {
|
|
4401
|
+
await writeUpdateAttempt(layout, record3);
|
|
4402
4402
|
}
|
|
4403
|
-
async function writeUpdateAttemptFixture(layout,
|
|
4403
|
+
async function writeUpdateAttemptFixture(layout, record3) {
|
|
4404
4404
|
await writeUpdateAttempt(layout, {
|
|
4405
|
-
...
|
|
4406
|
-
version:
|
|
4407
|
-
confirmBy:
|
|
4408
|
-
status:
|
|
4405
|
+
...record3,
|
|
4406
|
+
version: record3.version ?? 1,
|
|
4407
|
+
confirmBy: record3.confirmBy ?? record3.appliedAt + DEFAULT_UPDATE_CONFIRM_WINDOW_MS,
|
|
4408
|
+
status: record3.status ?? "pending"
|
|
4409
4409
|
});
|
|
4410
4410
|
}
|
|
4411
4411
|
async function settleUpdateAttemptOnStart(layout, opts = {}) {
|
|
4412
|
-
const
|
|
4413
|
-
if (!
|
|
4412
|
+
const record3 = await readUpdateAttempt(layout);
|
|
4413
|
+
if (!record3 || record3.status !== "pending")
|
|
4414
4414
|
return { kind: "none" };
|
|
4415
4415
|
const now2 = opts.now ?? Date.now;
|
|
4416
|
-
const confirmAt = opts.confirmWindowMs ?
|
|
4416
|
+
const confirmAt = opts.confirmWindowMs ? record3.appliedAt + opts.confirmWindowMs : record3.confirmBy;
|
|
4417
4417
|
if (now2() <= confirmAt) {
|
|
4418
|
-
return { kind: "pending", confirmAt, record:
|
|
4418
|
+
return { kind: "pending", confirmAt, record: record3 };
|
|
4419
4419
|
}
|
|
4420
|
-
if (
|
|
4421
|
-
await rollbackToPreviousRelease(layout,
|
|
4420
|
+
if (record3.previousReleaseId) {
|
|
4421
|
+
await rollbackToPreviousRelease(layout, record3.previousReleaseId);
|
|
4422
4422
|
}
|
|
4423
4423
|
await writeUpdateAttempt(layout, {
|
|
4424
|
-
...
|
|
4424
|
+
...record3,
|
|
4425
4425
|
confirmBy: confirmAt,
|
|
4426
4426
|
status: "reverted",
|
|
4427
4427
|
failure: "update did not serve a verified turn before its confirmation deadline"
|
|
4428
4428
|
});
|
|
4429
|
-
return { kind: "rolled-back", record:
|
|
4429
|
+
return { kind: "rolled-back", record: record3 };
|
|
4430
4430
|
}
|
|
4431
4431
|
function describeIdentity(identity) {
|
|
4432
4432
|
if (!identity)
|
|
@@ -6864,13 +6864,13 @@ function parseAvailableCommands(value) {
|
|
|
6864
6864
|
for (const entry of value) {
|
|
6865
6865
|
if (!entry || typeof entry !== "object")
|
|
6866
6866
|
continue;
|
|
6867
|
-
const
|
|
6868
|
-
const rawName = typeof
|
|
6867
|
+
const record3 = entry;
|
|
6868
|
+
const rawName = typeof record3.name === "string" ? record3.name.trim().replace(/^\/+/, "") : "";
|
|
6869
6869
|
if (!rawName || rawName.length > 80 || seen.has(rawName))
|
|
6870
6870
|
continue;
|
|
6871
6871
|
seen.add(rawName);
|
|
6872
|
-
const description = typeof
|
|
6873
|
-
const input =
|
|
6872
|
+
const description = typeof record3.description === "string" && record3.description.trim() ? record3.description.trim().slice(0, 300) : void 0;
|
|
6873
|
+
const input = record3.input;
|
|
6874
6874
|
const hintRaw = input && typeof input.hint === "string" ? input.hint : void 0;
|
|
6875
6875
|
const inputHint = hintRaw && hintRaw.trim() ? hintRaw.trim().slice(0, 120) : void 0;
|
|
6876
6876
|
result.push({
|
|
@@ -6901,7 +6901,8 @@ function isPiAcpHarness(agentLabel) {
|
|
|
6901
6901
|
function withoutOneTrailingLineEnding(text2) {
|
|
6902
6902
|
if (/\r?\n\r?\n$/.test(text2))
|
|
6903
6903
|
return text2;
|
|
6904
|
-
|
|
6904
|
+
const stripped = text2.replace(/\r?\n$/, "");
|
|
6905
|
+
return stripped || text2;
|
|
6905
6906
|
}
|
|
6906
6907
|
function normalizeStreamDelta(text2, agentLabel) {
|
|
6907
6908
|
return agentLabel && PI_ACP_HARNESS.test(agentLabel) ? withoutOneTrailingLineEnding(text2) : text2;
|
|
@@ -7727,12 +7728,12 @@ function parseAdvertisedConfigOptions(raw, preferredModelId, includeLaunchEffort
|
|
|
7727
7728
|
for (const entry of Array.isArray(configOptions) ? configOptions : []) {
|
|
7728
7729
|
if (!entry || typeof entry !== "object")
|
|
7729
7730
|
continue;
|
|
7730
|
-
const
|
|
7731
|
-
const id =
|
|
7732
|
-
const category =
|
|
7731
|
+
const record3 = entry;
|
|
7732
|
+
const id = record3.id;
|
|
7733
|
+
const category = record3.category;
|
|
7733
7734
|
if (typeof id !== "string" || typeof category !== "string")
|
|
7734
7735
|
continue;
|
|
7735
|
-
const rawChoices = Array.isArray(
|
|
7736
|
+
const rawChoices = Array.isArray(record3.options) ? record3.options : [];
|
|
7736
7737
|
const choices = [];
|
|
7737
7738
|
for (const rawChoice of rawChoices) {
|
|
7738
7739
|
if (!rawChoice || typeof rawChoice !== "object")
|
|
@@ -7749,7 +7750,7 @@ function parseAdvertisedConfigOptions(raw, preferredModelId, includeLaunchEffort
|
|
|
7749
7750
|
result.push({
|
|
7750
7751
|
id,
|
|
7751
7752
|
category,
|
|
7752
|
-
...typeof
|
|
7753
|
+
...typeof record3.currentValue === "string" ? { currentValue: record3.currentValue } : {},
|
|
7753
7754
|
options: category === "model" ? sortModelChoicesNewestFirst(choices) : choices
|
|
7754
7755
|
});
|
|
7755
7756
|
}
|
|
@@ -7857,8 +7858,8 @@ function credentialedPiCustomProviders(env) {
|
|
|
7857
7858
|
};
|
|
7858
7859
|
if (Array.isArray(providers)) {
|
|
7859
7860
|
for (const provider of providers) {
|
|
7860
|
-
const
|
|
7861
|
-
remember(
|
|
7861
|
+
const record3 = provider;
|
|
7862
|
+
remember(record3?.name ?? record3?.id, record3);
|
|
7862
7863
|
}
|
|
7863
7864
|
} else if (providers && typeof providers === "object") {
|
|
7864
7865
|
for (const [name, config] of Object.entries(providers)) {
|
|
@@ -8183,6 +8184,9 @@ function isAgentCommand(value) {
|
|
|
8183
8184
|
return Boolean(source && typeof source.id === "string" && typeof source.authorId === "string" && typeof source.body === "string" && typeof source.createdAt === "number" && Array.isArray(source.attachments));
|
|
8184
8185
|
}
|
|
8185
8186
|
|
|
8187
|
+
// packages/api-contract/dist/artifacts.js
|
|
8188
|
+
var ARTIFACT_MAXIMUM_BYTES = 2 * 1024 * 1024;
|
|
8189
|
+
|
|
8186
8190
|
// packages/api-contract/dist/system-events.js
|
|
8187
8191
|
var SERVER_EVENT_KINDS = [
|
|
8188
8192
|
"joined",
|
|
@@ -18047,6 +18051,106 @@ var GrantRunnerServer = class {
|
|
|
18047
18051
|
}
|
|
18048
18052
|
};
|
|
18049
18053
|
|
|
18054
|
+
// apps/body/dist/connector-runner.js
|
|
18055
|
+
function toolName(call) {
|
|
18056
|
+
const raw = `${call.title ?? ""} ${call.kind ?? ""}`;
|
|
18057
|
+
const match = raw.match(/(?:^|__|\b)(use_credential|fetch_credential|grant_app_access|revoke_app_access)\b/);
|
|
18058
|
+
return match?.[1] ?? "";
|
|
18059
|
+
}
|
|
18060
|
+
var SQUIRE_EVENT_CLASS = {
|
|
18061
|
+
fetch_credential: "approval",
|
|
18062
|
+
// the credential was read in clear
|
|
18063
|
+
grant_app_access: "approval",
|
|
18064
|
+
// a host was added to a key
|
|
18065
|
+
revoke_app_access: "vault-change"
|
|
18066
|
+
// access removed on the owner's behalf
|
|
18067
|
+
};
|
|
18068
|
+
function record(call) {
|
|
18069
|
+
return call && typeof call === "object" ? call : {};
|
|
18070
|
+
}
|
|
18071
|
+
function serializedSize(value) {
|
|
18072
|
+
if (value == null)
|
|
18073
|
+
return 0;
|
|
18074
|
+
if (typeof value === "string")
|
|
18075
|
+
return value.length;
|
|
18076
|
+
try {
|
|
18077
|
+
return JSON.stringify(value).length;
|
|
18078
|
+
} catch {
|
|
18079
|
+
return 0;
|
|
18080
|
+
}
|
|
18081
|
+
}
|
|
18082
|
+
function squireUsageFromToolCall(call) {
|
|
18083
|
+
const tool = toolName(call);
|
|
18084
|
+
if (!tool)
|
|
18085
|
+
return void 0;
|
|
18086
|
+
const args = record(call.rawInput);
|
|
18087
|
+
const result = record(call.content ?? call.rawOutput);
|
|
18088
|
+
const resultPayload = record(result.content ?? result);
|
|
18089
|
+
const url = typeof args.url === "string" ? args.url : "";
|
|
18090
|
+
const method = typeof args.method === "string" ? args.method.toUpperCase() : tool;
|
|
18091
|
+
const operation = url ? `${method} ${url}` : `${method} ${String(args.reference ?? "")}`.trim();
|
|
18092
|
+
const statusCode = typeof resultPayload.status === "number" ? resultPayload.status : /failed|error|denied/i.test(call.status ?? "") ? 0 : 200;
|
|
18093
|
+
return {
|
|
18094
|
+
ref: String(args.reference ?? args.service ?? ""),
|
|
18095
|
+
service: typeof args.service === "string" ? args.service : null,
|
|
18096
|
+
operation: operation.slice(0, 300),
|
|
18097
|
+
statusCode,
|
|
18098
|
+
bytes: serializedSize(resultPayload.body ?? resultPayload),
|
|
18099
|
+
...typeof args.grant_id === "string" ? { grantId: args.grant_id } : {},
|
|
18100
|
+
...SQUIRE_EVENT_CLASS[tool] ? { eventClass: SQUIRE_EVENT_CLASS[tool] } : {}
|
|
18101
|
+
};
|
|
18102
|
+
}
|
|
18103
|
+
var ConnectorUsageRecorder = class {
|
|
18104
|
+
batches = /* @__PURE__ */ new Map();
|
|
18105
|
+
turns = /* @__PURE__ */ new Map();
|
|
18106
|
+
record(turn, usage2) {
|
|
18107
|
+
if (!usage2.ref)
|
|
18108
|
+
return;
|
|
18109
|
+
const existing = this.batches.get(turn.requestId) ?? [];
|
|
18110
|
+
existing.push(usage2);
|
|
18111
|
+
this.batches.set(turn.requestId, existing);
|
|
18112
|
+
if (!this.turns.has(turn.requestId))
|
|
18113
|
+
this.turns.set(turn.requestId, turn);
|
|
18114
|
+
}
|
|
18115
|
+
/** Everything recorded for this turn so far; used by tests and diagnostics. */
|
|
18116
|
+
pending(requestId) {
|
|
18117
|
+
return this.batches.get(requestId) ?? [];
|
|
18118
|
+
}
|
|
18119
|
+
/**
|
|
18120
|
+
* Publish the turn's whole batch as ONE operation call and clear it.
|
|
18121
|
+
* Returns the published record count (0 when nothing was recorded or the
|
|
18122
|
+
* publish failed — a failed usage report never fails the agent turn).
|
|
18123
|
+
*/
|
|
18124
|
+
async flush(api, requestId) {
|
|
18125
|
+
const usage2 = this.batches.get(requestId);
|
|
18126
|
+
const turn = this.turns.get(requestId);
|
|
18127
|
+
if (!usage2?.length || !turn)
|
|
18128
|
+
return 0;
|
|
18129
|
+
this.batches.delete(requestId);
|
|
18130
|
+
this.turns.delete(requestId);
|
|
18131
|
+
try {
|
|
18132
|
+
await api.execute("postConnectionUsage", {
|
|
18133
|
+
requestId: turn.requestId,
|
|
18134
|
+
agentId: turn.agentId,
|
|
18135
|
+
...turn.roomId ? { roomId: turn.roomId } : {},
|
|
18136
|
+
...turn.cornerId ? { cornerId: turn.cornerId } : {},
|
|
18137
|
+
usage: usage2
|
|
18138
|
+
});
|
|
18139
|
+
return usage2.length;
|
|
18140
|
+
} catch (error) {
|
|
18141
|
+
console.error("[connector] connection usage report failed:", error);
|
|
18142
|
+
return 0;
|
|
18143
|
+
}
|
|
18144
|
+
}
|
|
18145
|
+
};
|
|
18146
|
+
function captureConnectionUsage(recorder, turn, calls) {
|
|
18147
|
+
for (const call of calls) {
|
|
18148
|
+
const usage2 = squireUsageFromToolCall(call);
|
|
18149
|
+
if (usage2)
|
|
18150
|
+
recorder.record(turn, usage2);
|
|
18151
|
+
}
|
|
18152
|
+
}
|
|
18153
|
+
|
|
18050
18154
|
// apps/body/dist/server-command-intake.js
|
|
18051
18155
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
18052
18156
|
import { mkdir as mkdir3, writeFile as writeFile4 } from "node:fs/promises";
|
|
@@ -18312,6 +18416,20 @@ description: How to answer inside a Beeline Room.
|
|
|
18312
18416
|
# Using Beeline
|
|
18313
18417
|
|
|
18314
18418
|
You are answering inside a Room whose filesystem is read-only. ${BEELINE_ROOM_CAPABILITIES}
|
|
18419
|
+
|
|
18420
|
+
## Tools and the Workbench
|
|
18421
|
+
|
|
18422
|
+
A **tool** is something you can use once a human pairs it; a **key** is the credential that tool holds for that human. You spend a key through the mounted connector and never see the credential itself.
|
|
18423
|
+
|
|
18424
|
+
This build knows one tool: Trusty Squire - vaulted credentials and a browser that signs in for you. Wallet and Tailscale are named in the Workbench but not yet available.
|
|
18425
|
+
|
|
18426
|
+
You NEVER pair a tool and never ask for a raw credential in chat. When a task needs one you do not have, say so plainly, name the tool that would solve it, and tell the person exactly where to go: Settings \u2192 Workbench \u2192 Tools.
|
|
18427
|
+
|
|
18428
|
+
Keys are sovereign: they belong to the human who provisioned them. You cannot use another member's key and must not ask a member to share one.
|
|
18429
|
+
|
|
18430
|
+
## Showing a mock
|
|
18431
|
+
|
|
18432
|
+
When a design decision needs eyes, show it instead of describing it. Build ONE self-contained HTML page and post it with beeline-agent post_artifact (mime "text/html", pass the document as html). Everything is inline: a single <style> element for all CSS and data: URLs for any image - no script, no external dependencies, no network references. The validator refuses every <script>, <link>, <iframe>, <object>, <embed>, <form>, inline event handler, and http(s) URL, so a page that reaches for the network never posts. Use the Obsidian Refined tokens: grayscale surfaces, one brass accent #d7af5f, 3px radii, IBM Plex Sans/Mono type. Lay the user stories out as frames - one bordered, labelled block per story, so each story can be judged on its own. After posting, ask for feedback here in the corner: the artifact is the thing people react to, not your prose.
|
|
18315
18433
|
`;
|
|
18316
18434
|
}
|
|
18317
18435
|
function beelineReviewSkillMarkdown(releaseId) {
|
|
@@ -18437,8 +18555,8 @@ function openRouterModelId(model, env = {}) {
|
|
|
18437
18555
|
}
|
|
18438
18556
|
function parseOpenRouterEndpoints(payload) {
|
|
18439
18557
|
const data = payload?.data;
|
|
18440
|
-
const
|
|
18441
|
-
const raw = Array.isArray(
|
|
18558
|
+
const record3 = data && typeof data === "object" ? data : {};
|
|
18559
|
+
const raw = Array.isArray(record3.endpoints) ? record3.endpoints : [];
|
|
18442
18560
|
const endpoints = [];
|
|
18443
18561
|
for (const entry of raw) {
|
|
18444
18562
|
if (!entry || typeof entry !== "object")
|
|
@@ -18453,11 +18571,11 @@ function parseOpenRouterEndpoints(payload) {
|
|
|
18453
18571
|
const supported = Array.isArray(endpoint2.supported_parameters) ? endpoint2.supported_parameters : [];
|
|
18454
18572
|
endpoints.push({ provider, uptime, contextLength, tools: supported.includes("tools") });
|
|
18455
18573
|
}
|
|
18456
|
-
const architecture =
|
|
18574
|
+
const architecture = record3.architecture && typeof record3.architecture === "object" ? record3.architecture : {};
|
|
18457
18575
|
const modalities = Array.isArray(architecture.input_modalities) ? architecture.input_modalities.filter((value) => typeof value === "string" && value.length > 0) : void 0;
|
|
18458
18576
|
return {
|
|
18459
18577
|
endpoints,
|
|
18460
|
-
contextLength: typeof
|
|
18578
|
+
contextLength: typeof record3.context_length === "number" ? record3.context_length : advertisedContextLength(endpoints),
|
|
18461
18579
|
inputModalities: modalities?.length ? modalities : void 0
|
|
18462
18580
|
};
|
|
18463
18581
|
}
|
|
@@ -19904,8 +20022,8 @@ function toolCallText(content) {
|
|
|
19904
20022
|
}
|
|
19905
20023
|
if (!value || typeof value !== "object")
|
|
19906
20024
|
return;
|
|
19907
|
-
const
|
|
19908
|
-
for (const [key, nested] of Object.entries(
|
|
20025
|
+
const record3 = value;
|
|
20026
|
+
for (const [key, nested] of Object.entries(record3)) {
|
|
19909
20027
|
if (["text", "content", "message", "error", "output"].includes(key.toLowerCase())) {
|
|
19910
20028
|
walk(nested, depth + 1);
|
|
19911
20029
|
}
|
|
@@ -20204,8 +20322,8 @@ function shellPayload(toolCall) {
|
|
|
20204
20322
|
return true;
|
|
20205
20323
|
if (!rawInput || typeof rawInput !== "object" || Array.isArray(rawInput))
|
|
20206
20324
|
return false;
|
|
20207
|
-
const
|
|
20208
|
-
return typeof
|
|
20325
|
+
const record3 = rawInput;
|
|
20326
|
+
return typeof record3.command === "string" || typeof record3.cmd === "string";
|
|
20209
20327
|
}
|
|
20210
20328
|
var ROOM_MOUNTED_MCP_SERVERS = [
|
|
20211
20329
|
READ_ONLY_MCP_SERVER_NAME,
|
|
@@ -20217,10 +20335,10 @@ var TOOL_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
|
|
|
20217
20335
|
function permissionRecord(rawInput) {
|
|
20218
20336
|
return rawInput && typeof rawInput === "object" && !Array.isArray(rawInput) ? rawInput : void 0;
|
|
20219
20337
|
}
|
|
20220
|
-
function dispatchedPayloadIsShell(
|
|
20221
|
-
if (!
|
|
20338
|
+
function dispatchedPayloadIsShell(record3) {
|
|
20339
|
+
if (!record3)
|
|
20222
20340
|
return false;
|
|
20223
|
-
return DISPATCHER_TOOL_INPUT_KEYS.some((key) => key in
|
|
20341
|
+
return DISPATCHER_TOOL_INPUT_KEYS.some((key) => key in record3 && shellPayload({ rawInput: record3[key] }));
|
|
20224
20342
|
}
|
|
20225
20343
|
function toolIdentityCandidates(toolCall) {
|
|
20226
20344
|
const candidates = [];
|
|
@@ -20229,9 +20347,9 @@ function toolIdentityCandidates(toolCall) {
|
|
|
20229
20347
|
candidates.push(value.trim());
|
|
20230
20348
|
};
|
|
20231
20349
|
add(toolCall?.title);
|
|
20232
|
-
const
|
|
20350
|
+
const record3 = permissionRecord(toolCall?.rawInput);
|
|
20233
20351
|
for (const key of DISPATCHER_TOOL_NAME_KEYS)
|
|
20234
|
-
add(
|
|
20352
|
+
add(record3?.[key]);
|
|
20235
20353
|
return candidates;
|
|
20236
20354
|
}
|
|
20237
20355
|
function normalizedServerName(name) {
|
|
@@ -20241,8 +20359,8 @@ function resolveMountedMcpToolCall(request, mountedServers) {
|
|
|
20241
20359
|
const toolCall = request.toolCall;
|
|
20242
20360
|
if (shellPayload(toolCall))
|
|
20243
20361
|
return void 0;
|
|
20244
|
-
const
|
|
20245
|
-
if (dispatchedPayloadIsShell(
|
|
20362
|
+
const record3 = permissionRecord(toolCall?.rawInput);
|
|
20363
|
+
if (dispatchedPayloadIsShell(record3))
|
|
20246
20364
|
return void 0;
|
|
20247
20365
|
const candidates = toolIdentityCandidates(toolCall);
|
|
20248
20366
|
for (const server of mountedServers) {
|
|
@@ -20519,25 +20637,25 @@ async function explainEmptyAgentTurn(input) {
|
|
|
20519
20637
|
const streamFact = describeEmptyTurn(input.result, input.agentLabel);
|
|
20520
20638
|
if (!isPiAcpHarness(input.agentLabel))
|
|
20521
20639
|
return { reason: streamFact };
|
|
20522
|
-
const
|
|
20523
|
-
if (!
|
|
20640
|
+
const record3 = await readPiTurnRecord({ agentEnv: input.agentEnv, sessionId: input.sessionId });
|
|
20641
|
+
if (!record3)
|
|
20524
20642
|
return { reason: `pi left no readable turn record; ${streamFact}` };
|
|
20525
|
-
switch (
|
|
20643
|
+
switch (record3.kind) {
|
|
20526
20644
|
case "error":
|
|
20527
|
-
return { reason:
|
|
20645
|
+
return { reason: record3.reason, record: record3 };
|
|
20528
20646
|
case "empty":
|
|
20529
20647
|
return {
|
|
20530
|
-
reason: `the model ended its turn with no text (stop reason ${
|
|
20531
|
-
record:
|
|
20648
|
+
reason: `the model ended its turn with no text (stop reason ${record3.stopReason})`,
|
|
20649
|
+
record: record3
|
|
20532
20650
|
};
|
|
20533
20651
|
case "answer":
|
|
20534
20652
|
return {
|
|
20535
|
-
recoveredText:
|
|
20653
|
+
recoveredText: record3.text,
|
|
20536
20654
|
reason: "pi recorded the answer but the ACP stream delivered no text",
|
|
20537
|
-
record:
|
|
20655
|
+
record: record3
|
|
20538
20656
|
};
|
|
20539
20657
|
case "missing":
|
|
20540
|
-
return { reason: `pi recorded no assistant message for this turn; ${streamFact}`, record:
|
|
20658
|
+
return { reason: `pi recorded no assistant message for this turn; ${streamFact}`, record: record3 };
|
|
20541
20659
|
}
|
|
20542
20660
|
}
|
|
20543
20661
|
function shouldRetryEmptyTurn(explanation) {
|
|
@@ -20564,10 +20682,10 @@ function turnFailureReasonWithProvider(reason, providers) {
|
|
|
20564
20682
|
const served = describeTurnProviders(providers);
|
|
20565
20683
|
return served ? `${reason} \xB7 ${served}` : reason;
|
|
20566
20684
|
}
|
|
20567
|
-
function isAccountOrProviderRefusal(
|
|
20568
|
-
if (!
|
|
20685
|
+
function isAccountOrProviderRefusal(record3) {
|
|
20686
|
+
if (!record3 || record3.kind !== "error" || record3.status === void 0)
|
|
20569
20687
|
return false;
|
|
20570
|
-
return [401, 402, 403, 407, 408, 429].includes(
|
|
20688
|
+
return [401, 402, 403, 407, 408, 429].includes(record3.status) || record3.status >= 500;
|
|
20571
20689
|
}
|
|
20572
20690
|
|
|
20573
20691
|
// apps/body/dist/response-directives.js
|
|
@@ -20824,11 +20942,11 @@ var TurnTrace = class {
|
|
|
20824
20942
|
this.end(phase);
|
|
20825
20943
|
this.promptSettled();
|
|
20826
20944
|
}
|
|
20827
|
-
const
|
|
20828
|
-
await this.options.sink?.write(
|
|
20945
|
+
const record3 = this.snapshot(outcome, reason);
|
|
20946
|
+
await this.options.sink?.write(record3).catch((error) => {
|
|
20829
20947
|
console.error("[thin-core] turn trace write failed:", error);
|
|
20830
20948
|
});
|
|
20831
|
-
return
|
|
20949
|
+
return record3;
|
|
20832
20950
|
}
|
|
20833
20951
|
};
|
|
20834
20952
|
function round(ms) {
|
|
@@ -20853,9 +20971,9 @@ function formatTurnAttempt(attempt) {
|
|
|
20853
20971
|
parts.push(`${attempt.toolCalls} tool call${attempt.toolCalls === 1 ? "" : "s"}`);
|
|
20854
20972
|
return parts.join(" \xB7 ");
|
|
20855
20973
|
}
|
|
20856
|
-
function formatTurnTraceLine(
|
|
20857
|
-
const head = `${
|
|
20858
|
-
return [head, ...
|
|
20974
|
+
function formatTurnTraceLine(record3) {
|
|
20975
|
+
const head = `${record3.surface} ${record3.roomId} turn ${record3.requestId} ${record3.outcome} ${formatDuration(record3.totalMs)}`;
|
|
20976
|
+
return [head, ...record3.attempts.map((attempt) => formatTurnAttempt(attempt))].join("\n ");
|
|
20859
20977
|
}
|
|
20860
20978
|
function turnTraceDirectory(runtimeDir) {
|
|
20861
20979
|
return resolve17(runtimeDir, "turn-traces");
|
|
@@ -20877,16 +20995,16 @@ var TurnTraceFile = class {
|
|
|
20877
20995
|
path(now2 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))()) {
|
|
20878
20996
|
return resolve17(this.directory, traceFileName(now2));
|
|
20879
20997
|
}
|
|
20880
|
-
write(
|
|
20998
|
+
write(record3) {
|
|
20881
20999
|
this.tail = this.tail.catch(() => void 0).then(async () => {
|
|
20882
21000
|
const now2 = (this.options.clock ?? (() => /* @__PURE__ */ new Date()))();
|
|
20883
21001
|
const path = this.path(now2);
|
|
20884
21002
|
await mkdir8(this.directory, { recursive: true, mode: 448 });
|
|
20885
|
-
await appendFile(path, `${JSON.stringify(
|
|
21003
|
+
await appendFile(path, `${JSON.stringify(record3)}
|
|
20886
21004
|
`, { mode: 384 });
|
|
20887
21005
|
await this.prune(now2);
|
|
20888
21006
|
const log2 = this.options.log ?? ((line) => console.log(line));
|
|
20889
|
-
log2(`[thin-core] turn trace ${formatTurnTraceLine(
|
|
21007
|
+
log2(`[thin-core] turn trace ${formatTurnTraceLine(record3)}${this.announced ? "" : `
|
|
20890
21008
|
recorded in ${path}`}`);
|
|
20891
21009
|
this.announced = true;
|
|
20892
21010
|
});
|
|
@@ -22100,6 +22218,11 @@ function cornerReviewerInstruction(input) {
|
|
|
22100
22218
|
const headSha = input.headSha ?? "<head sha>";
|
|
22101
22219
|
return `Checks are green on PR #${number} at ${headSha}. Review it now with the beeline-review skill against that exact head. FAIL: reply \`@${author}\` with the confirmed findings to fix. PASS: call the approve_merge tool for ${headSha}, then reply \`@${author} approved ${headSha}, merge\`. Never merge yourself. Never say you are holding or waiting for checks.`;
|
|
22102
22220
|
}
|
|
22221
|
+
function cornerSelfReviewerInstruction(input) {
|
|
22222
|
+
if (!input.reviewerHandle || !input.agentHandle || !input.openedByAgent || input.agentHandle.replace(/^@/, "") !== input.reviewerHandle.replace(/^@/, ""))
|
|
22223
|
+
return void 0;
|
|
22224
|
+
return "You are this Room's reviewer, so your own pull request needs no review: do not request one, do not tag any agent for review, and merge yourself with gh once checks pass and no hold exists.";
|
|
22225
|
+
}
|
|
22103
22226
|
var CORNER_AUTHOR_CONTRACT = `The objective text is the user's ask. Keep it verbatim in your head and do not reinterpret it.
|
|
22104
22227
|
Before any code, write its end-user story in one sentence: "a person who does X sees Y".
|
|
22105
22228
|
If the objective reports a defect, reproduce it first at the layer where it lives: the command, request, or tap sequence, and what was observed.
|
|
@@ -22159,7 +22282,7 @@ function serialized(value) {
|
|
|
22159
22282
|
return "";
|
|
22160
22283
|
}
|
|
22161
22284
|
}
|
|
22162
|
-
function
|
|
22285
|
+
function record2(value) {
|
|
22163
22286
|
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
22164
22287
|
}
|
|
22165
22288
|
function clampBytes(value, maxBytes) {
|
|
@@ -22199,7 +22322,7 @@ function filePaths(value, worktreePath) {
|
|
|
22199
22322
|
candidate.forEach((entry) => visit(entry));
|
|
22200
22323
|
return;
|
|
22201
22324
|
}
|
|
22202
|
-
const object =
|
|
22325
|
+
const object = record2(candidate);
|
|
22203
22326
|
if (object)
|
|
22204
22327
|
Object.entries(object).forEach(([entryKey, entry]) => visit(entry, entryKey));
|
|
22205
22328
|
};
|
|
@@ -22207,9 +22330,9 @@ function filePaths(value, worktreePath) {
|
|
|
22207
22330
|
return [...paths];
|
|
22208
22331
|
}
|
|
22209
22332
|
function resultStatus(call) {
|
|
22210
|
-
const content =
|
|
22333
|
+
const content = record2(call.content) ?? (typeof call.content === "string" ? (() => {
|
|
22211
22334
|
try {
|
|
22212
|
-
return
|
|
22335
|
+
return record2(JSON.parse(call.content));
|
|
22213
22336
|
} catch {
|
|
22214
22337
|
return void 0;
|
|
22215
22338
|
}
|
|
@@ -22224,7 +22347,7 @@ function resultStatus(call) {
|
|
|
22224
22347
|
return /(?:failed|error|denied)/i.test(call.status ?? "") ? "error" : "ok";
|
|
22225
22348
|
}
|
|
22226
22349
|
function toolArguments(call) {
|
|
22227
|
-
const raw =
|
|
22350
|
+
const raw = record2(call.rawInput);
|
|
22228
22351
|
const command = typeof call.rawInput === "string" ? call.rawInput : typeof raw?.command === "string" ? raw.command : typeof raw?.cmd === "string" ? raw.cmd : void 0;
|
|
22229
22352
|
if (command)
|
|
22230
22353
|
return { command: clampBytes(redactToolDetail(command), TOOL_ARGUMENT_MAX_BYTES) };
|
|
@@ -22462,7 +22585,8 @@ var MonolithCornerTurnLoop = class {
|
|
|
22462
22585
|
headSha: restore.lifecycle?.pr?.headSha
|
|
22463
22586
|
});
|
|
22464
22587
|
}
|
|
22465
|
-
|
|
22588
|
+
const selfReviewerInstruction = cornerSelfReviewerInstruction(reviewerInput);
|
|
22589
|
+
this.cornerTurnEndNudge = reviewerInstruction ?? selfReviewerInstruction ?? cornerMergeInstruction(configuration.yoloMode, configuration.reviewerHandle);
|
|
22466
22590
|
await mkdir12(this.options.worktreePath, { recursive: true });
|
|
22467
22591
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
22468
22592
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
@@ -22612,10 +22736,10 @@ var MonolithCornerTurnLoop = class {
|
|
|
22612
22736
|
...reviewerInstruction ? [reviewerInstruction] : [
|
|
22613
22737
|
configuration.reviewerHandle ? `Once the pull request exists, reply with its full URL and end the turn; do not tag the reviewer, check, or wait for CI.` : 'Once the pull request exists, reply only with its full URL and end the turn; do not check or wait for CI. On a later checks turn, call pr_checks_status. Merge only when checks="passed", held=false, and approvalPending=false; if checks="unknown", reply in this corner with the tool reason and stop instead of retrying. Only a later explicit human resume clears a hold.',
|
|
22614
22738
|
CORNER_AUTHOR_CONTRACT,
|
|
22615
|
-
cornerMergeInstruction(configuration.yoloMode, configuration.reviewerHandle)
|
|
22739
|
+
selfReviewerInstruction ?? cornerMergeInstruction(configuration.yoloMode, configuration.reviewerHandle)
|
|
22616
22740
|
],
|
|
22617
22741
|
"Do not tag the user when a corner turn finishes: the server posts the merge summary card and its push already cover completion. Tag a human only mid-turn, and only when you need a decision or input.",
|
|
22618
|
-
"Never restate server check or merge notes. On a checks turn, say nothing unless you merge or push a fix, then use one short line. Never merge while approvalPending is true. When approval is pending, wait for the reviewer to tag you. Never merge another pull request."
|
|
22742
|
+
"Never restate server check or merge notes. On a checks turn, say nothing unless you merge or push a fix, then use one short line. Never merge while approvalPending is true. When approval is pending, wait for the reviewer to tag you. Never merge another pull request. Never create a schedule to poll pr_checks_status or the merge gate: the green transition wakes the reviewer and the reviewer's approval tag wakes you, and tagging any agent other than the configured reviewer cannot clear the gate. If a schedule wakes you in this corner anyway, follow the same rule as a checks turn: say nothing unless you merge, push a fix, or report a genuinely new blocker."
|
|
22619
22743
|
] : [
|
|
22620
22744
|
"This is a chat-only corner with no repository or GitHub workflow.",
|
|
22621
22745
|
"Work in this corner's writable workspace. Use write_scratch_file or ordinary tools to create files, then attach_file to send them back to the corner.",
|
|
@@ -22781,7 +22905,7 @@ ${trigger}`,
|
|
|
22781
22905
|
const pendingToolActivities = /* @__PURE__ */ new Map();
|
|
22782
22906
|
let lastNarratedToolCall;
|
|
22783
22907
|
let activityAttempt = 0;
|
|
22784
|
-
const publishToolCalls = (calls, settledOnly) => {
|
|
22908
|
+
const publishToolCalls = (calls, settledOnly, exceptKey) => {
|
|
22785
22909
|
calls.forEach((call, index) => {
|
|
22786
22910
|
const key = `${activityAttempt}:${toolCallKey(call, index)}`;
|
|
22787
22911
|
if (settledOnly && !observedToolCalls.has(key)) {
|
|
@@ -22791,7 +22915,7 @@ ${trigger}`,
|
|
|
22791
22915
|
if (narration2)
|
|
22792
22916
|
lastNarratedToolCall = key;
|
|
22793
22917
|
}
|
|
22794
|
-
if (settledOnly || publishedToolCalls.has(key) || !toolCallSettled(call))
|
|
22918
|
+
if (settledOnly || publishedToolCalls.has(key) || !toolCallSettled(call) || key === exceptKey)
|
|
22795
22919
|
return;
|
|
22796
22920
|
publishedToolCalls.add(key);
|
|
22797
22921
|
const narration = pendingToolNarrations.get(key) ?? "";
|
|
@@ -22827,12 +22951,18 @@ ${trigger}`,
|
|
|
22827
22951
|
});
|
|
22828
22952
|
});
|
|
22829
22953
|
};
|
|
22830
|
-
const flushToolCalls = async (calls, finalReply) => {
|
|
22954
|
+
const flushToolCalls = async (calls, finalReply, final = false) => {
|
|
22831
22955
|
await this.activityTail;
|
|
22832
22956
|
if (lastNarratedToolCall && pendingToolNarrations.get(lastNarratedToolCall) === finalReply)
|
|
22833
22957
|
pendingToolNarrations.delete(lastNarratedToolCall);
|
|
22834
22958
|
publishToolCalls(calls, false);
|
|
22835
22959
|
await this.activityTail;
|
|
22960
|
+
if (this.options.connectorUsage) {
|
|
22961
|
+
captureConnectionUsage(this.options.connectorUsage, { requestId, agentId: this.agent.publicKey, cornerId }, calls);
|
|
22962
|
+
if (final)
|
|
22963
|
+
await this.options.connectorUsage.flush(api, requestId);
|
|
22964
|
+
}
|
|
22965
|
+
await this.activityTail;
|
|
22836
22966
|
publishToolCalls(calls, false);
|
|
22837
22967
|
await this.activityTail;
|
|
22838
22968
|
};
|
|
@@ -22864,6 +22994,7 @@ ${trigger}`,
|
|
|
22864
22994
|
}, void 0, (calls) => {
|
|
22865
22995
|
trace.toolCalls(calls);
|
|
22866
22996
|
publishToolCalls(calls, true);
|
|
22997
|
+
publishToolCalls(calls, false, lastNarratedToolCall);
|
|
22867
22998
|
});
|
|
22868
22999
|
};
|
|
22869
23000
|
let result = await runPrompt();
|
|
@@ -22901,7 +23032,7 @@ ${trigger}`,
|
|
|
22901
23032
|
if (!reply && explained?.recoveredText)
|
|
22902
23033
|
reply = durableReplyText(explained.recoveredText);
|
|
22903
23034
|
reply = [replyBeforeNudge, reply].filter(Boolean).join("\n\n");
|
|
22904
|
-
await flushToolCalls(result.toolCalls, reply);
|
|
23035
|
+
await flushToolCalls(result.toolCalls, reply, true);
|
|
22905
23036
|
for (const call of result.toolCalls) {
|
|
22906
23037
|
const failure = toolCallFailureLine(call);
|
|
22907
23038
|
if (failure)
|
|
@@ -23632,6 +23763,8 @@ var RoomRuntimeCoordinator = class {
|
|
|
23632
23763
|
/** One command-grant runner per daemon; Rooms and corners register their checkouts on it. */
|
|
23633
23764
|
grantRunner;
|
|
23634
23765
|
grantRunnerServer;
|
|
23766
|
+
/** Connection usage capture, batched per agent turn. */
|
|
23767
|
+
connectorUsage;
|
|
23635
23768
|
constructor(runtime, configPath, baseConfig, options) {
|
|
23636
23769
|
this.configPath = configPath;
|
|
23637
23770
|
this.baseConfig = baseConfig;
|
|
@@ -23646,6 +23779,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
23646
23779
|
agentId: this.agent.publicKey
|
|
23647
23780
|
});
|
|
23648
23781
|
this.grantRunnerServer = new GrantRunnerServer(this.grantRunner);
|
|
23782
|
+
this.connectorUsage = new ConnectorUsageRecorder();
|
|
23649
23783
|
this.watchdogStaleMs = options.watchdogStaleMs ?? DEFAULT_ROOM_WATCHDOG_STALE_MS;
|
|
23650
23784
|
this.reconcileHeartbeatMs = options.reconcileHeartbeatMs ?? DEFAULT_RECONCILE_HEARTBEAT_MS;
|
|
23651
23785
|
this.drainDeadlineMs = options.drainDeadlineMs ?? DEFAULT_DRAIN_DEADLINE_MS;
|
|
@@ -23962,6 +24096,7 @@ var RoomRuntimeCoordinator = class {
|
|
|
23962
24096
|
cornerId: corner.cornerId,
|
|
23963
24097
|
grantRunner: this.grantRunner,
|
|
23964
24098
|
...grantRunnerEndpoint ? { grantRunnerEndpoint } : {},
|
|
24099
|
+
connectorUsage: this.connectorUsage,
|
|
23965
24100
|
parentRoomId: corner.parentRoomId,
|
|
23966
24101
|
workspaceId: this.runtime.communityId,
|
|
23967
24102
|
...corner.openedBy ? { openedBy: corner.openedBy } : {},
|
|
@@ -25668,7 +25803,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
25668
25803
|
libDir: resolve25(this.#layout.releasesRoot, this.#loadedRelease)
|
|
25669
25804
|
}).catch(() => void 0) ?? {};
|
|
25670
25805
|
const to = await readInstalledBundleIdentity(this.#layout).catch(() => void 0) ?? {};
|
|
25671
|
-
const
|
|
25806
|
+
const record3 = {
|
|
25672
25807
|
version: 1,
|
|
25673
25808
|
from,
|
|
25674
25809
|
to,
|
|
@@ -25679,7 +25814,7 @@ var ManagedUpdateHandoff = class _ManagedUpdateHandoff {
|
|
|
25679
25814
|
status: "pending",
|
|
25680
25815
|
...this.#requiredProbeIds.length > 0 ? { requiredProbeIds: this.#requiredProbeIds, confirmedProbeIds: [] } : {}
|
|
25681
25816
|
};
|
|
25682
|
-
await writeUpdateAttempt(this.#layout,
|
|
25817
|
+
await writeUpdateAttempt(this.#layout, record3);
|
|
25683
25818
|
} else if (this.#requiredProbeIds.length > 0) {
|
|
25684
25819
|
const requiredProbeIds = [
|
|
25685
25820
|
.../* @__PURE__ */ new Set([...attempt.requiredProbeIds ?? [], ...this.#requiredProbeIds])
|
|
@@ -26198,11 +26333,11 @@ async function readFailureRecord(runtimeDir) {
|
|
|
26198
26333
|
return void 0;
|
|
26199
26334
|
}
|
|
26200
26335
|
}
|
|
26201
|
-
async function writeFailureRecord(runtimeDir,
|
|
26336
|
+
async function writeFailureRecord(runtimeDir, record3) {
|
|
26202
26337
|
const path = daemonFailurePath(runtimeDir);
|
|
26203
26338
|
const staged = `${path}.${process.pid}.tmp`;
|
|
26204
26339
|
await mkdir19(dirname15(path), { recursive: true, mode: 448 });
|
|
26205
|
-
await writeFile14(staged, `${JSON.stringify(
|
|
26340
|
+
await writeFile14(staged, `${JSON.stringify(record3, null, 2)}
|
|
26206
26341
|
`, { mode: 384 });
|
|
26207
26342
|
await rename6(staged, path);
|
|
26208
26343
|
}
|
|
@@ -26210,13 +26345,13 @@ async function recordDaemonStartFailure(runtimeDir, error, now2 = Date.now()) {
|
|
|
26210
26345
|
const prior = await readFailureRecord(runtimeDir);
|
|
26211
26346
|
const failures = [...prior?.failures ?? [], now2].filter((failure) => now2 - failure <= DAEMON_FAILURE_WINDOW_MS);
|
|
26212
26347
|
const distressed = failures.length >= DAEMON_FAILURE_LIMIT;
|
|
26213
|
-
const
|
|
26348
|
+
const record3 = {
|
|
26214
26349
|
version: 1,
|
|
26215
26350
|
failures,
|
|
26216
26351
|
lastError: (error instanceof Error ? error.message : String(error)).slice(0, 1e3),
|
|
26217
26352
|
...distressed ? { distressedAt: now2 } : {}
|
|
26218
26353
|
};
|
|
26219
|
-
await writeFailureRecord(runtimeDir,
|
|
26354
|
+
await writeFailureRecord(runtimeDir, record3);
|
|
26220
26355
|
return { distressed, count: failures.length, path: daemonFailurePath(runtimeDir) };
|
|
26221
26356
|
}
|
|
26222
26357
|
async function clearDaemonStartFailures(runtimeDir) {
|