usebeeline 0.0.92 → 0.0.95
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 +299 -55
- package/package.json +1 -1
package/dist/usebeeline.mjs
CHANGED
|
@@ -2413,7 +2413,7 @@ var require_websocket = __commonJS({
|
|
|
2413
2413
|
var EventEmitter2 = __require("events");
|
|
2414
2414
|
var https = __require("https");
|
|
2415
2415
|
var http = __require("http");
|
|
2416
|
-
var
|
|
2416
|
+
var net2 = __require("net");
|
|
2417
2417
|
var tls = __require("tls");
|
|
2418
2418
|
var { randomBytes: randomBytes7, createHash: createHash9 } = __require("crypto");
|
|
2419
2419
|
var { Duplex, Readable } = __require("stream");
|
|
@@ -3157,12 +3157,12 @@ var require_websocket = __commonJS({
|
|
|
3157
3157
|
}
|
|
3158
3158
|
function netConnect(options) {
|
|
3159
3159
|
options.path = options.socketPath;
|
|
3160
|
-
return
|
|
3160
|
+
return net2.connect(options);
|
|
3161
3161
|
}
|
|
3162
3162
|
function tlsConnect(options) {
|
|
3163
3163
|
options.path = void 0;
|
|
3164
3164
|
if (!options.servername && options.servername !== "") {
|
|
3165
|
-
options.servername =
|
|
3165
|
+
options.servername = net2.isIP(options.host) ? "" : options.host;
|
|
3166
3166
|
}
|
|
3167
3167
|
return tls.connect(options);
|
|
3168
3168
|
}
|
|
@@ -4654,6 +4654,19 @@ var init_self_update = __esm({
|
|
|
4654
4654
|
}
|
|
4655
4655
|
});
|
|
4656
4656
|
|
|
4657
|
+
// apps/body/dist/network-family-bootstrap.js
|
|
4658
|
+
import * as net from "node:net";
|
|
4659
|
+
var NETWORK_FAMILY_ATTEMPT_TIMEOUT_MS = 5e3;
|
|
4660
|
+
function configureNetworkFamilyDefaults(network = net) {
|
|
4661
|
+
if (typeof network.setDefaultAutoSelectFamilyAttemptTimeout === "function") {
|
|
4662
|
+
network.setDefaultAutoSelectFamilyAttemptTimeout(NETWORK_FAMILY_ATTEMPT_TIMEOUT_MS);
|
|
4663
|
+
return "timeout";
|
|
4664
|
+
}
|
|
4665
|
+
network.setDefaultAutoSelectFamily?.(false);
|
|
4666
|
+
return "autoselection-disabled";
|
|
4667
|
+
}
|
|
4668
|
+
configureNetworkFamilyDefaults();
|
|
4669
|
+
|
|
4657
4670
|
// apps/body/dist/cli.js
|
|
4658
4671
|
import { dirname as dirname17, resolve as resolve30 } from "node:path";
|
|
4659
4672
|
import { readFile as readFile15, unlink as unlink5, writeFile as writeFile16 } from "node:fs/promises";
|
|
@@ -7893,6 +7906,16 @@ var ModelSelectionUnavailableError = class extends Error {
|
|
|
7893
7906
|
this.guidance = input.guidance;
|
|
7894
7907
|
}
|
|
7895
7908
|
};
|
|
7909
|
+
function withEffectiveCurrentValues(options, selection) {
|
|
7910
|
+
if (!selection || !selection.model && !selection.effort)
|
|
7911
|
+
return options;
|
|
7912
|
+
return options.map((option) => {
|
|
7913
|
+
const target = modelSelectionTargets(selection).find((entry) => entry.categories.includes(option.category));
|
|
7914
|
+
if (!target?.value || option.currentValue === target.value)
|
|
7915
|
+
return option;
|
|
7916
|
+
return { ...option, currentValue: target.value };
|
|
7917
|
+
});
|
|
7918
|
+
}
|
|
7896
7919
|
function modelSelectionTargets(selection) {
|
|
7897
7920
|
return [
|
|
7898
7921
|
{ categories: ["model"], label: "model", value: selection.model },
|
|
@@ -8010,7 +8033,24 @@ async function withAgentModelCatalog(agent, agentEnv, selection, inspect, limits
|
|
|
8010
8033
|
}
|
|
8011
8034
|
}
|
|
8012
8035
|
async function fetchAgentModelCatalog(agent, agentEnv, selection, limits = {}) {
|
|
8013
|
-
return withAgentModelCatalog(agent, agentEnv, selection, async ({ raw, catalog }) => ({
|
|
8036
|
+
return withAgentModelCatalog(agent, agentEnv, selection, async ({ client, sessionId, raw, catalog }) => ({
|
|
8037
|
+
raw,
|
|
8038
|
+
catalog: await filterModelChoicesByLiveValidation(client, sessionId, catalog)
|
|
8039
|
+
}), limits);
|
|
8040
|
+
}
|
|
8041
|
+
async function filterModelChoicesByLiveValidation(client, sessionId, catalog) {
|
|
8042
|
+
const modelAxis = catalog.find((axis) => axis.category === "model");
|
|
8043
|
+
if (!modelAxis)
|
|
8044
|
+
return catalog;
|
|
8045
|
+
const available = [];
|
|
8046
|
+
for (const choice of modelAxis.options) {
|
|
8047
|
+
try {
|
|
8048
|
+
await applyAgentModelSelection(client, sessionId, catalog, { model: choice.id });
|
|
8049
|
+
available.push(choice);
|
|
8050
|
+
} catch {
|
|
8051
|
+
}
|
|
8052
|
+
}
|
|
8053
|
+
return catalog.map((axis) => axis === modelAxis ? { ...axis, options: available } : axis);
|
|
8014
8054
|
}
|
|
8015
8055
|
async function validateAgentModelSelection(agent, agentEnv, selection) {
|
|
8016
8056
|
return withAgentModelCatalog(agent, agentEnv, selection, async ({ client, sessionId, raw, catalog }) => {
|
|
@@ -8066,8 +8106,12 @@ import { readFile, writeFile } from "node:fs/promises";
|
|
|
8066
8106
|
import { resolve as resolve5 } from "node:path";
|
|
8067
8107
|
var MODEL_CATALOG_PROBE_TIMEOUT_MS = 3e4;
|
|
8068
8108
|
var MODEL_CATALOG_HASH_FILE = "model-catalog.sha256";
|
|
8069
|
-
function modelCatalogHash(options, selection) {
|
|
8070
|
-
return createHash("sha256").update(JSON.stringify({
|
|
8109
|
+
function modelCatalogHash(options, selection, startupUnavailable) {
|
|
8110
|
+
return createHash("sha256").update(JSON.stringify({
|
|
8111
|
+
options,
|
|
8112
|
+
selection: selection ?? null,
|
|
8113
|
+
startupUnavailable: startupUnavailable ?? null
|
|
8114
|
+
})).digest("hex");
|
|
8071
8115
|
}
|
|
8072
8116
|
async function withTimeout(work, timeoutMs, what) {
|
|
8073
8117
|
let timer;
|
|
@@ -8093,8 +8137,9 @@ async function syncAgentModelCatalog(input) {
|
|
|
8093
8137
|
...configuration.model ? { model: configuration.model } : {},
|
|
8094
8138
|
...configuration.effort ? { effort: configuration.effort } : {}
|
|
8095
8139
|
} : input.runtimeSelection;
|
|
8096
|
-
const { catalog } = await withTimeout(fetchCatalog(input.agent, input.agentEnv, selection), input.timeoutMs ?? MODEL_CATALOG_PROBE_TIMEOUT_MS, "model catalog probe");
|
|
8097
|
-
const
|
|
8140
|
+
const { catalog } = await withTimeout(fetchCatalog(input.agent, input.agentEnv, input.startupUnavailable ? void 0 : selection), input.timeoutMs ?? MODEL_CATALOG_PROBE_TIMEOUT_MS, "model catalog probe");
|
|
8141
|
+
const effectiveCatalog = input.startupUnavailable ? catalog : withEffectiveCurrentValues(catalog, selection);
|
|
8142
|
+
const hash = modelCatalogHash(effectiveCatalog, selection, input.startupUnavailable);
|
|
8098
8143
|
const previous = await readFile(hashPath, "utf8").catch(() => "");
|
|
8099
8144
|
if (previous.trim() === hash)
|
|
8100
8145
|
return "unchanged";
|
|
@@ -8102,8 +8147,9 @@ async function syncAgentModelCatalog(input) {
|
|
|
8102
8147
|
agentId: input.agentId,
|
|
8103
8148
|
workspaceId: input.workspaceId,
|
|
8104
8149
|
// `fetchAgentModelCatalog` already applied the category allow-list.
|
|
8105
|
-
options:
|
|
8106
|
-
...selection ? { selection } : {}
|
|
8150
|
+
options: effectiveCatalog,
|
|
8151
|
+
...selection ? { selection } : {},
|
|
8152
|
+
...input.startupUnavailable ? { unavailable: input.startupUnavailable } : {}
|
|
8107
8153
|
});
|
|
8108
8154
|
await writeFile(hashPath, `${hash}
|
|
8109
8155
|
`, { mode: 384 });
|
|
@@ -8134,7 +8180,7 @@ function isAgentCommand(value) {
|
|
|
8134
8180
|
if (!["input", "resume", "stop"].includes(String(c2.action)) || !Number.isInteger(c2.agentDepth) || Number(c2.agentDepth) < 0 || Number(c2.agentDepth) > 3)
|
|
8135
8181
|
return false;
|
|
8136
8182
|
const source = c2.source;
|
|
8137
|
-
return Boolean(source && typeof source.id === "string" && typeof source.authorId === "string" && typeof source.body === "string" && typeof source.createdAt === "number" && Array.isArray(source.attachments)
|
|
8183
|
+
return Boolean(source && typeof source.id === "string" && typeof source.authorId === "string" && typeof source.body === "string" && typeof source.createdAt === "number" && Array.isArray(source.attachments));
|
|
8138
8184
|
}
|
|
8139
8185
|
|
|
8140
8186
|
// packages/api-contract/dist/system-events.js
|
|
@@ -18201,6 +18247,7 @@ function isAgentPairingCode(value) {
|
|
|
18201
18247
|
|
|
18202
18248
|
// apps/body/dist/beeline-skill.js
|
|
18203
18249
|
var USING_BEELINE_SKILL_NAME = "using-beeline";
|
|
18250
|
+
var BEELINE_REVIEW_SKILL_NAME = "beeline-review";
|
|
18204
18251
|
var BEELINE_ROOM_CAPABILITIES = [
|
|
18205
18252
|
"The repository filesystem is read-only in this Room session.",
|
|
18206
18253
|
"You may address any Room member, including another agent, by writing @name in your reply; the server routes that mention to them. Each turn prompt lists the Room members and the exact spelling that tags each one - use those spellings, and never guess or reuse one from an older message.",
|
|
@@ -18213,6 +18260,8 @@ var BEELINE_ROOM_CAPABILITIES = [
|
|
|
18213
18260
|
`To react to things that HAPPEN in this Room rather than only to what is said to you, call beeline-agent subscribe_events with the kinds you want (${SERVER_EVENT_KINDS.join(", ")}); each one then wakes you for a turn. It replaces your list, so send every kind you want - list_event_subscriptions shows the current one. You do this yourself: nobody has to configure it for you. grant-decided carries the grant id and status and resumes the turn that asked for the grant.`,
|
|
18214
18261
|
"To state something that happened so the Room and other agents can act on it, call beeline-agent emit_event with your own agent:<slug> kind, one sentence, and optionally the agent members to wake. Chains of events are bounded and a refused emit posts nothing.",
|
|
18215
18262
|
"When repository work is needed, you MUST call beeline-agent open_corner with a name of at most three words - it titles the corner everywhere - and a complete objective of no more than 24 words. The host-governed call is the only way to start write work.",
|
|
18263
|
+
"Never open a corner from your own reading of a person's ask. For every ask, first reply on one line `Proposed corner: <name> \u2014 <objective>`, using the exact title and objective you would pass to open_corner, then stop and wait. If one message contains several asks, list one numbered `Proposed corner:` line per ask; `go on 1 and 3` opens exactly those objectives and leaves the others proposed. A person's `go`, `yes`, or equivalent opens exactly the proposed corner; if they edit it, their edited text is the objective. Skip this ceremony only when the message itself explicitly commands a corner and states its scope, such as `open a corner and do X` or `go build X in a corner`; open that scope immediately.",
|
|
18264
|
+
"Agreement is not action: never merely acknowledge an ask. Reply with a proposed corner, a question, or a line beginning `parked:` with the reason.",
|
|
18216
18265
|
"When open_corner succeeds, the server posts the corner card: do not announce or restate the opening. End the turn with nothing more unless the person asked something else.",
|
|
18217
18266
|
"Never claim an action or reply happened unless the prompt or a tool result proves it."
|
|
18218
18267
|
].join(" ");
|
|
@@ -18265,6 +18314,86 @@ description: How to answer inside a Beeline Room.
|
|
|
18265
18314
|
You are answering inside a Room whose filesystem is read-only. ${BEELINE_ROOM_CAPABILITIES}
|
|
18266
18315
|
`;
|
|
18267
18316
|
}
|
|
18317
|
+
function beelineReviewSkillMarkdown(releaseId) {
|
|
18318
|
+
return `---
|
|
18319
|
+
name: beeline-review
|
|
18320
|
+
description: Review a corner pull request against its objective and the Beeline merge gate.
|
|
18321
|
+
---
|
|
18322
|
+
|
|
18323
|
+
<!-- beeline-release: ${releaseId} -->
|
|
18324
|
+
|
|
18325
|
+
# Beeline pull-request review
|
|
18326
|
+
|
|
18327
|
+
Follow these steps in order. Do not skip or reorder them.
|
|
18328
|
+
|
|
18329
|
+
## 1. Isolate the revision
|
|
18330
|
+
|
|
18331
|
+
- Run \`gh pr view N --json headRefOid,files\` and record \`headRefOid\`.
|
|
18332
|
+
- Run \`gh pr diff N\`.
|
|
18333
|
+
- Check out that exact head in a new scratch git worktree. Never use the author's worktree.
|
|
18334
|
+
- Review and test only the recorded revision. If the head moves, start over.
|
|
18335
|
+
|
|
18336
|
+
## 2. P0 - OBJECTIVE FULFILLED, DEMONSTRATED
|
|
18337
|
+
|
|
18338
|
+
- Quote the corner objective verbatim.
|
|
18339
|
+
- Derive its end-user story in one sentence: \`a user who does X sees Y\`.
|
|
18340
|
+
- Make Y happen against the built PR head: run the app or affected service and perform X.
|
|
18341
|
+
- If no interactive surface is reachable, run the narrowest test or script that exercises the exact user path and prints the observable Y.
|
|
18342
|
+
- Record the command and the observed Y.
|
|
18343
|
+
- A unit test of an inner function, a log line, \`the code looks right\`, or any other proxy does not count.
|
|
18344
|
+
- If the user-visible Y cannot be produced, FAIL now. Nothing below can rescue the review.
|
|
18345
|
+
- State whether the diff fulfills that objective and only that objective.
|
|
18346
|
+
|
|
18347
|
+
## 3. Empirical pass second
|
|
18348
|
+
|
|
18349
|
+
- Run the repository typecheck and tests touched by the diff.
|
|
18350
|
+
- If the objective names a user path, exercise that path.
|
|
18351
|
+
- Record every command and exit code.
|
|
18352
|
+
- A review with no executed command is invalid and must FAIL.
|
|
18353
|
+
|
|
18354
|
+
## 4. Adversarial pass
|
|
18355
|
+
|
|
18356
|
+
- For every changed function, name one concrete input or sequence that breaks it.
|
|
18357
|
+
- If none is found, write \`none found\` for that function.
|
|
18358
|
+
|
|
18359
|
+
## 5. Verify before reporting
|
|
18360
|
+
|
|
18361
|
+
- Confirm every finding by reading the exact line or by running a command.
|
|
18362
|
+
- Put unconfirmed concerns under plausible findings. They never block.
|
|
18363
|
+
|
|
18364
|
+
## 6. Bloat guard
|
|
18365
|
+
|
|
18366
|
+
- Compare net lines with the objective.
|
|
18367
|
+
- FAIL backwards-compatibility shims, dual paths, feature flags, or abstractions with one caller.
|
|
18368
|
+
- FAIL machinery the objective did not ask for.
|
|
18369
|
+
|
|
18370
|
+
## 7. Security and data
|
|
18371
|
+
|
|
18372
|
+
- Check credentials, authorization boundaries, and destructive migrations.
|
|
18373
|
+
|
|
18374
|
+
## 8. Gate and verdict
|
|
18375
|
+
|
|
18376
|
+
- The merge gate is open only when \`pr_checks_status\` reports checks=passed, held=false, approvalPending=false.
|
|
18377
|
+
- Green \`gh pr checks\` alone never opens the gate.
|
|
18378
|
+
- Always use this exact verdict shape:
|
|
18379
|
+
|
|
18380
|
+
\`objective quoted:\`
|
|
18381
|
+
\`user story:\`
|
|
18382
|
+
\`how Y was demonstrated (or FAIL):\`
|
|
18383
|
+
\`commands run + results:\`
|
|
18384
|
+
\`critical findings (block):\`
|
|
18385
|
+
\`plausible findings (do not block):\`
|
|
18386
|
+
\`net lines:\`
|
|
18387
|
+
\`decision: PASS|FAIL\`
|
|
18388
|
+
|
|
18389
|
+
Then take exactly one action:
|
|
18390
|
+
|
|
18391
|
+
- FAIL: reply \`@author\` with the confirmed findings; do not merge.
|
|
18392
|
+
- PASS with pending checks: reply \`approved pending checks <reviewed sha>\` and stop.
|
|
18393
|
+
- PASS with the gate open and your yolo on: run \`gh pr merge --squash --match-head-commit <reviewed sha> N\`.
|
|
18394
|
+
- PASS with the gate open and your yolo off: reply \`approved <reviewed sha>\` and stop.
|
|
18395
|
+
`;
|
|
18396
|
+
}
|
|
18268
18397
|
|
|
18269
18398
|
// apps/body/dist/external-mcp-capabilities.js
|
|
18270
18399
|
var SQUIRE_MCP_VERSION = "1.1.12";
|
|
@@ -18862,7 +18991,10 @@ var SHARED_CREDENTIALS = [
|
|
|
18862
18991
|
{ dir: "pi", source: ".pi/agent/auth.json", target: "auth.json" }
|
|
18863
18992
|
];
|
|
18864
18993
|
var GOOSE_SHARED_CONFIG_FILES = ["config.yaml", "secrets.yaml"];
|
|
18865
|
-
var BEELINE_DEFAULT_SKILL_NAMES = [
|
|
18994
|
+
var BEELINE_DEFAULT_SKILL_NAMES = [
|
|
18995
|
+
BEELINE_REVIEW_SKILL_NAME,
|
|
18996
|
+
USING_BEELINE_SKILL_NAME
|
|
18997
|
+
];
|
|
18866
18998
|
var OPERATOR_SKILL_SOURCE_DIRS = [
|
|
18867
18999
|
".agents/skills",
|
|
18868
19000
|
".claude/skills",
|
|
@@ -18941,7 +19073,8 @@ async function prepareRoomAgentHome(input) {
|
|
|
18941
19073
|
}
|
|
18942
19074
|
async function provisionAgentSkillsAndMcp(root, operatorHome, skillReleaseId, failClosed, sharedSkills, skillDir, openRouterRouting) {
|
|
18943
19075
|
const managedSkills = [
|
|
18944
|
-
{ name: USING_BEELINE_SKILL_NAME, content: usingBeelineSkillMarkdown(skillReleaseId) }
|
|
19076
|
+
{ name: USING_BEELINE_SKILL_NAME, content: usingBeelineSkillMarkdown(skillReleaseId) },
|
|
19077
|
+
{ name: BEELINE_REVIEW_SKILL_NAME, content: beelineReviewSkillMarkdown(skillReleaseId) }
|
|
18945
19078
|
];
|
|
18946
19079
|
const shared = await resolveSharedSkillSources(operatorHome, sharedSkills);
|
|
18947
19080
|
await provisionManagedSkillsDir(resolve13(root, skillDir, "skills"), managedSkills, shared, sharedSkills.length === 0);
|
|
@@ -19617,6 +19750,12 @@ var AgentTurnStream = class {
|
|
|
19617
19750
|
inFlight;
|
|
19618
19751
|
/** Closed lanes publish nothing more, so the answer never queues behind a draft. */
|
|
19619
19752
|
closed = false;
|
|
19753
|
+
/**
|
|
19754
|
+
* The retract this lane already sent. A settled turn that throws afterwards
|
|
19755
|
+
* reaches the same retract a second time, and one empty lane is the whole
|
|
19756
|
+
* point: asking twice would only be a second write saying what is already so.
|
|
19757
|
+
*/
|
|
19758
|
+
retraction;
|
|
19620
19759
|
constructor(options) {
|
|
19621
19760
|
this.options = options;
|
|
19622
19761
|
}
|
|
@@ -19676,31 +19815,56 @@ var AgentTurnStream = class {
|
|
|
19676
19815
|
this.closed = true;
|
|
19677
19816
|
this.pending = void 0;
|
|
19678
19817
|
}
|
|
19818
|
+
/**
|
|
19819
|
+
* Dissolve the draft, publishing nothing.
|
|
19820
|
+
*
|
|
19821
|
+
* Every ending uses this: the settle below calls it once the durable reply is
|
|
19822
|
+
* on the wire, and a turn that THROWS calls it directly. A throw never
|
|
19823
|
+
* reaches a settle, and `close()` alone only stops future writes — the last
|
|
19824
|
+
* snapshot stays live on the page, so a turn the Room has already reported
|
|
19825
|
+
* stopped or failed keeps a half-written answer visibly in progress under it.
|
|
19826
|
+
*/
|
|
19827
|
+
async retract() {
|
|
19828
|
+
this.close();
|
|
19829
|
+
this.retraction ??= (async () => {
|
|
19830
|
+
await this.inFlight;
|
|
19831
|
+
const { api, agentId, roomId, requestId, label } = this.options;
|
|
19832
|
+
await api.execute("retractAgentLiveOutput", {
|
|
19833
|
+
agentId,
|
|
19834
|
+
roomId,
|
|
19835
|
+
turnId: requestId,
|
|
19836
|
+
kind: "draft"
|
|
19837
|
+
}).catch((error) => console.error(`[thin-core] ${label} draft retract failed:`, error));
|
|
19838
|
+
})();
|
|
19839
|
+
await this.retraction;
|
|
19840
|
+
}
|
|
19679
19841
|
/**
|
|
19680
19842
|
* Post the durable reply under the turn's request id and dissolve the draft.
|
|
19681
19843
|
* An empty reply settles through the turn receipt instead, and the lane is
|
|
19682
19844
|
* retracted either way.
|
|
19845
|
+
*
|
|
19846
|
+
* The durable reply is this turn's answer and its last word. The draft lane
|
|
19847
|
+
* is presentation, so a refused retract is logged like a refused draft and
|
|
19848
|
+
* the turn still settles complete: raising here failed a turn that had
|
|
19849
|
+
* already answered, which posts a `failed` receipt and inscribes "<agent>
|
|
19850
|
+
* could not answer" UNDER the answer the reader is looking at. The reader
|
|
19851
|
+
* loses nothing by it either — the phone ends a retracted draft on the
|
|
19852
|
+
* turn's own complete receipt (`visibleLiveOverlays`).
|
|
19683
19853
|
*/
|
|
19684
19854
|
async settle(reply, fields = {}, onReplyPosted) {
|
|
19685
19855
|
this.close();
|
|
19686
|
-
const { api,
|
|
19856
|
+
const { api, roomId, requestId } = this.options;
|
|
19687
19857
|
if (reply) {
|
|
19688
|
-
|
|
19858
|
+
await api.execute("postRoomMessage", {
|
|
19689
19859
|
roomId,
|
|
19690
19860
|
requestId,
|
|
19691
19861
|
text: reply,
|
|
19692
19862
|
presentation: "message",
|
|
19693
19863
|
...fields
|
|
19694
19864
|
});
|
|
19695
|
-
onReplyPosted?.(
|
|
19865
|
+
onReplyPosted?.();
|
|
19696
19866
|
}
|
|
19697
|
-
await this.
|
|
19698
|
-
await api.execute("retractAgentLiveOutput", {
|
|
19699
|
-
agentId,
|
|
19700
|
-
roomId,
|
|
19701
|
-
turnId: requestId,
|
|
19702
|
-
kind: "draft"
|
|
19703
|
-
});
|
|
19867
|
+
await this.retract();
|
|
19704
19868
|
}
|
|
19705
19869
|
};
|
|
19706
19870
|
|
|
@@ -19710,13 +19874,18 @@ function redactToolDetail(value) {
|
|
|
19710
19874
|
return value.replace(/\b(["']?)(api[_-]?key|token|secret|password|passwd|authorization|credential|cookie|private[_-]?key)\1\s*[:=]\s*(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,}\]]+)/gi, '"$2": "[REDACTED]"').replace(/\b(?:export\s+)?[A-Za-z_][A-Za-z0-9_]*=(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\S+)/g, (assignment) => `${assignment.slice(0, assignment.indexOf("="))}=[REDACTED]`).replace(/\b(?:gh[pousr]_[A-Za-z0-9_]{12,}|github_pat_[A-Za-z0-9_]{12,})\b/gi, "[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, "[REDACTED]").replace(/\b(Bearer\s+)[^\s,]+/gi, "$1[REDACTED]").replace(/\bsk-[A-Za-z0-9_-]{12,}\b/g, "[REDACTED]").replace(/(--?(?:api[_-]?key|token|secret|password|authorization|credential|cookie)\s+)(?:"[^"]*"|'[^']*'|\S+)/gi, "$1[REDACTED]");
|
|
19711
19875
|
}
|
|
19712
19876
|
function distillTurnFailureReason(error) {
|
|
19877
|
+
if (error instanceof ModelSelectionUnavailableError) {
|
|
19878
|
+
return { text: "model selection unavailable", kind: "model-selection-unavailable" };
|
|
19879
|
+
}
|
|
19713
19880
|
const raw = error instanceof Error ? error.message : typeof error === "string" ? error : error && typeof error === "object" && "message" in error ? String(error.message) : error == null ? "" : String(error);
|
|
19714
19881
|
const firstLine = raw.split(/\r?\n/).map((line) => line.trim()).find((line) => line && !/^at\s/.test(line)) ?? "";
|
|
19715
19882
|
const stripped = firstLine.replace(/^(?:[A-Za-z]*Error|Error):\s*/, "").replace(/\s+/g, " ");
|
|
19716
19883
|
const clean4 = redactToolDetail(stripped).trim();
|
|
19717
19884
|
if (!clean4)
|
|
19718
|
-
return "turn failed";
|
|
19719
|
-
return
|
|
19885
|
+
return { text: "turn failed" };
|
|
19886
|
+
return {
|
|
19887
|
+
text: clean4.length > TURN_FAILURE_REASON_MAX ? `${clean4.slice(0, TURN_FAILURE_REASON_MAX - 1)}\u2026` : clean4
|
|
19888
|
+
};
|
|
19720
19889
|
}
|
|
19721
19890
|
|
|
19722
19891
|
// apps/body/dist/tool-call-failure.js
|
|
@@ -19750,6 +19919,9 @@ function toolCallText(content) {
|
|
|
19750
19919
|
function isFailedToolCall(call) {
|
|
19751
19920
|
return /^(?:failed|error|denied|rejected)$/i.test(call.status ?? "");
|
|
19752
19921
|
}
|
|
19922
|
+
function isCompletedToolCall(call) {
|
|
19923
|
+
return /^completed$/i.test(call.status ?? "");
|
|
19924
|
+
}
|
|
19753
19925
|
function toolCallFailureLine(call) {
|
|
19754
19926
|
if (!isFailedToolCall(call))
|
|
19755
19927
|
return void 0;
|
|
@@ -19760,14 +19932,17 @@ function toolCallFailureLine(call) {
|
|
|
19760
19932
|
|
|
19761
19933
|
// apps/body/dist/session-config-fingerprint.js
|
|
19762
19934
|
function sessionConfigFingerprint(input) {
|
|
19763
|
-
|
|
19935
|
+
const fingerprint = [
|
|
19764
19936
|
input.model ?? "",
|
|
19765
19937
|
input.effort ?? "",
|
|
19766
19938
|
input.soul?.name ?? "",
|
|
19767
19939
|
input.soul?.instructions ?? "",
|
|
19768
19940
|
input.agentName ?? "",
|
|
19769
19941
|
input.yoloMode ?? false
|
|
19770
|
-
]
|
|
19942
|
+
];
|
|
19943
|
+
if (input.reviewerHandle !== void 0)
|
|
19944
|
+
fingerprint.push(input.reviewerHandle);
|
|
19945
|
+
return JSON.stringify(fingerprint);
|
|
19771
19946
|
}
|
|
19772
19947
|
|
|
19773
19948
|
// apps/body/dist/pi-mcp-bridge.js
|
|
@@ -21078,23 +21253,23 @@ function isRoomMcpPermissionRequest(request, mountedServers = ROOM_MOUNTED_MCP_S
|
|
|
21078
21253
|
return false;
|
|
21079
21254
|
return isMountedMcpToolPermissionRequest(request, mountedServers);
|
|
21080
21255
|
}
|
|
21081
|
-
function isScheduledPrompt(item
|
|
21082
|
-
if (item.type !== "system"
|
|
21256
|
+
function isScheduledPrompt(item) {
|
|
21257
|
+
if (item.type !== "system")
|
|
21083
21258
|
return false;
|
|
21084
21259
|
if (item.systemEvent?.kind)
|
|
21085
21260
|
return item.systemEvent.kind === "schedule-ran";
|
|
21086
21261
|
return item.systemEvent?.verb === SCHEDULE_RAN_VERB;
|
|
21087
21262
|
}
|
|
21088
|
-
function inboxItemAuthorName(item,
|
|
21089
|
-
if (isScheduledPrompt(item
|
|
21263
|
+
function inboxItemAuthorName(item, names) {
|
|
21264
|
+
if (isScheduledPrompt(item))
|
|
21090
21265
|
return SCHEDULE_SCHEDULER_NAME;
|
|
21091
21266
|
const subject = item.systemEvent?.subject;
|
|
21092
21267
|
if (item.type === "system" && subject?.name)
|
|
21093
21268
|
return subject.name;
|
|
21094
21269
|
return names.get(item.authorId) ?? item.authorId.slice(0, 12);
|
|
21095
21270
|
}
|
|
21096
|
-
function inboxItemPromptBody(item
|
|
21097
|
-
return isScheduledPrompt(item
|
|
21271
|
+
function inboxItemPromptBody(item) {
|
|
21272
|
+
return isScheduledPrompt(item) ? item.systemEvent?.consequence ?? item.body : item.body;
|
|
21098
21273
|
}
|
|
21099
21274
|
function pendingGrantToolCall(call) {
|
|
21100
21275
|
if (!/(?:^|[._:/-])request_grant$/i.test(call.title ?? ""))
|
|
@@ -21558,6 +21733,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
21558
21733
|
const api = this.options.api;
|
|
21559
21734
|
this.busy = true;
|
|
21560
21735
|
const trace = this.beginTurnTrace(item.id);
|
|
21736
|
+
let liveStream;
|
|
21561
21737
|
try {
|
|
21562
21738
|
if (!this.memberNames.has(item.authorId))
|
|
21563
21739
|
await this.roster().catch(() => void 0);
|
|
@@ -21614,8 +21790,8 @@ var MonolithRoomTurnLoop = class {
|
|
|
21614
21790
|
"If the current task is only a nudge to respond, answer the most recent unanswered human message in the conversation instead of echoing the nudge.",
|
|
21615
21791
|
MAINTAIN_ASSIGNED_IDENTITY_DIRECTIVE
|
|
21616
21792
|
].join(" "),
|
|
21617
|
-
`Current task selected by the server from ${inboxItemAuthorName(item,
|
|
21618
|
-
roomMessagePrompt("", inboxItemPromptBody(item
|
|
21793
|
+
`Current task selected by the server from ${inboxItemAuthorName(item, names)}:`,
|
|
21794
|
+
roomMessagePrompt("", inboxItemPromptBody(item), item.attachments, delivered, this.acceptsImages())
|
|
21619
21795
|
].filter(Boolean).join("\n\n");
|
|
21620
21796
|
const stream = new AgentTurnStream({
|
|
21621
21797
|
api,
|
|
@@ -21624,6 +21800,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
21624
21800
|
requestId: item.id,
|
|
21625
21801
|
label: `monolith Room ${this.options.roomId}`
|
|
21626
21802
|
});
|
|
21803
|
+
liveStream = stream;
|
|
21627
21804
|
const runPrompt = async () => {
|
|
21628
21805
|
let nextPrompt = promptWithImages(buildPrompt(), attachmentImageBlocks(delivered, this.acceptsImages()));
|
|
21629
21806
|
let result2;
|
|
@@ -21661,7 +21838,9 @@ var MonolithRoomTurnLoop = class {
|
|
|
21661
21838
|
};
|
|
21662
21839
|
let result = await runPrompt();
|
|
21663
21840
|
trace.promptSettled();
|
|
21664
|
-
let
|
|
21841
|
+
let openCornerCall = openCornerToolCall(result.toolCalls);
|
|
21842
|
+
let cornerOpened = openedACorner(openCornerCall);
|
|
21843
|
+
let explained = cornerOpened ? void 0 : await this.explainEmpty(result);
|
|
21665
21844
|
if (explained && shouldRetryEmptyTurn(explained)) {
|
|
21666
21845
|
const silent = this.servingProviders();
|
|
21667
21846
|
const next = await this.repinNextProvider(trace, explained.reason);
|
|
@@ -21669,7 +21848,9 @@ var MonolithRoomTurnLoop = class {
|
|
|
21669
21848
|
console.warn(`[thin-core] monolith Room ${this.options.roomId} turn ${item.id}: ${turnFailureReasonWithProvider(explained.reason, silent)}; retrying on ${next}`);
|
|
21670
21849
|
result = await runPrompt();
|
|
21671
21850
|
trace.promptSettled();
|
|
21672
|
-
|
|
21851
|
+
openCornerCall = openCornerToolCall(result.toolCalls);
|
|
21852
|
+
cornerOpened = openedACorner(openCornerCall);
|
|
21853
|
+
explained = cornerOpened ? void 0 : await this.explainEmpty(result);
|
|
21673
21854
|
}
|
|
21674
21855
|
}
|
|
21675
21856
|
if (active.cancelled) {
|
|
@@ -21683,10 +21864,9 @@ var MonolithRoomTurnLoop = class {
|
|
|
21683
21864
|
} else if (resumedRequestId) {
|
|
21684
21865
|
console.log(`[thin-core] monolith Room ${this.options.roomId} turn ${resumedRequestId} resumed by grant decision ${item.id}`);
|
|
21685
21866
|
}
|
|
21686
|
-
const openCornerCall = result.toolCalls.find((call) => /(?:^|[._:/-])open_corner$/i.test(call.title ?? ""));
|
|
21687
21867
|
if (openCornerCall) {
|
|
21688
21868
|
console.log(`[thin-core] monolith Room ${this.options.roomId} tool call: ${openCornerCall.title} (${openCornerCall.status ?? "no status"})`);
|
|
21689
|
-
if (
|
|
21869
|
+
if (cornerOpened)
|
|
21690
21870
|
this.options.onCornerOpened?.();
|
|
21691
21871
|
}
|
|
21692
21872
|
for (const call of result?.toolCalls ?? []) {
|
|
@@ -21704,7 +21884,7 @@ var MonolithRoomTurnLoop = class {
|
|
|
21704
21884
|
}
|
|
21705
21885
|
console.warn(`[thin-core] monolith Room ${this.options.roomId} turn ${item.id}: ${explained.reason}`);
|
|
21706
21886
|
}
|
|
21707
|
-
if (
|
|
21887
|
+
if (cornerOpened) {
|
|
21708
21888
|
reply = "";
|
|
21709
21889
|
}
|
|
21710
21890
|
await trace.measure("publish", () => stream.settle(reply, reply ? {
|
|
@@ -21726,6 +21906,9 @@ var MonolithRoomTurnLoop = class {
|
|
|
21726
21906
|
await trace.finish("cancelled");
|
|
21727
21907
|
return;
|
|
21728
21908
|
}
|
|
21909
|
+
await liveStream?.retract().catch((retractError) => {
|
|
21910
|
+
console.error(`[thin-core] monolith Room ${this.options.roomId} draft retract failed:`, retractError);
|
|
21911
|
+
});
|
|
21729
21912
|
const reason = distillTurnFailureReason(error);
|
|
21730
21913
|
await api.execute("postAgentTurnReceipt", {
|
|
21731
21914
|
agentId: this.agent.publicKey,
|
|
@@ -21733,9 +21916,10 @@ var MonolithRoomTurnLoop = class {
|
|
|
21733
21916
|
requestId: item.id,
|
|
21734
21917
|
status: "failed",
|
|
21735
21918
|
generationId: this.commandContext.generationId,
|
|
21736
|
-
reason
|
|
21919
|
+
reason: reason.text,
|
|
21920
|
+
...reason.kind ? { reasonKind: reason.kind } : {}
|
|
21737
21921
|
});
|
|
21738
|
-
await trace.finish("failed", reason);
|
|
21922
|
+
await trace.finish("failed", reason.text);
|
|
21739
21923
|
throw error;
|
|
21740
21924
|
} finally {
|
|
21741
21925
|
this.busy = false;
|
|
@@ -21778,6 +21962,12 @@ var MonolithRoomTurnLoop = class {
|
|
|
21778
21962
|
}
|
|
21779
21963
|
}
|
|
21780
21964
|
};
|
|
21965
|
+
function openCornerToolCall(calls) {
|
|
21966
|
+
return calls.find((call) => /(?:^|[._:/-])open_corner$/i.test(call.title ?? ""));
|
|
21967
|
+
}
|
|
21968
|
+
function openedACorner(call) {
|
|
21969
|
+
return !!call && isCompletedToolCall(call);
|
|
21970
|
+
}
|
|
21781
21971
|
function roomMessagePrompt(author, body, attachments, delivered, harnessAcceptsImages = true) {
|
|
21782
21972
|
const message = body.trim() || "(shared attachments)";
|
|
21783
21973
|
const rendered = author ? `${author}: ${message}` : message;
|
|
@@ -21789,10 +21979,31 @@ var execFileAsync3 = promisify3(execFile4);
|
|
|
21789
21979
|
var TOOL_ARGUMENT_MAX_BYTES = 1200;
|
|
21790
21980
|
var TOOL_OUTPUT_MAX_BYTES = 3200;
|
|
21791
21981
|
var TOOL_PATH_LIMIT = 12;
|
|
21792
|
-
function cornerMergeInstruction(yoloMode) {
|
|
21982
|
+
function cornerMergeInstruction(yoloMode, reviewerHandle) {
|
|
21983
|
+
if (reviewerHandle)
|
|
21984
|
+
return `Commit, push, open the pull request, reply with the PR URL and then @${reviewerHandle} please review; never merge this PR yourself. If you asked any other agent to review in this corner, do not merge until they answer.`;
|
|
21793
21985
|
return yoloMode ? "Yolo is on: when the gate passes, merge this pull request with gh." : "Yolo is off: never merge; wait for explicit human approval in the app.";
|
|
21794
21986
|
}
|
|
21795
|
-
|
|
21987
|
+
function cornerReviewerInstruction(input) {
|
|
21988
|
+
if (!input.reviewerHandle || !input.agentHandle || input.openedByAgent || input.agentHandle.replace(/^@/, "") !== input.reviewerHandle.replace(/^@/, ""))
|
|
21989
|
+
return void 0;
|
|
21990
|
+
const author = input.authorHandle?.replace(/^@/, "") || "author";
|
|
21991
|
+
const number = input.pullRequestNumber ?? "N";
|
|
21992
|
+
return `Review PR #${number} with the beeline-review skill. If it fails, reply @${author} with the findings. If it passes and the gate (pr_checks_status: checks=passed, held=false, approvalPending=false) is open and YOUR yolo is on, merge with gh pr merge --squash --match-head-commit <sha you reviewed>; if your yolo is off, reply approved <sha> and stop; if checks are pending, reply approved pending checks <sha> and stop.`;
|
|
21993
|
+
}
|
|
21994
|
+
var CORNER_AUTHOR_CONTRACT = `The objective text is the user's ask. Keep it verbatim in your head and do not reinterpret it.
|
|
21995
|
+
Before any code, write its end-user story in one sentence: "a person who does X sees Y".
|
|
21996
|
+
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.
|
|
21997
|
+
Do not write a fix before you have seen the defect. Turn the reproduction into the regression test.
|
|
21998
|
+
Before opening the pull request, produce Y against the built change: run the app or affected service from your branch and perform X.
|
|
21999
|
+
If no interactive surface is reachable, run the narrowest test or script that exercises the exact user path and prints the observable Y.
|
|
22000
|
+
A unit test of an inner function, a log line, or reading the code is not a demonstration.
|
|
22001
|
+
The pull request body MUST contain two sections with exactly these headings: ## Reproduced and ## Demonstrated.
|
|
22002
|
+
Under ## Reproduced, give the steps or command and what was observed; write "not a defect report" for feature work.
|
|
22003
|
+
Under ## Demonstrated, give the command or steps that produced Y and what was observed.
|
|
22004
|
+
A pull request without both sections is not deliverable and the Room's reviewer will fail it.
|
|
22005
|
+
Change only what the objective asks. No unrequested features, flags, compatibility shims, or refactors.`;
|
|
22006
|
+
var CORNER_DELIVERY_NUDGE = "Before ending this turn, inspect the repository state and finish delivering the work: commit and push the intended changes and open the pull request if one does not exist. Decide yourself whether any remaining dirty work belongs to the objective; do not discard it merely to make the worktree clean. The pull request body must carry ## Reproduced and ## Demonstrated; if they are missing, add them before ending the turn.";
|
|
21796
22007
|
var CORNER_YOLO_MERGE_NUDGE = 'Yolo is on. Check the server merge gate with pr_checks_status now and, if checks="passed", held=false, and approvalPending=false, merge this pull request with gh. Otherwise stop without merging.';
|
|
21797
22008
|
function isCornerChecksTurn(trigger, restates) {
|
|
21798
22009
|
return Boolean(restates) || /\b(?:passed|failed) a check\b/i.test(trigger);
|
|
@@ -21977,6 +22188,10 @@ var MonolithCornerTurnLoop = class {
|
|
|
21977
22188
|
pinnedProviderOverride;
|
|
21978
22189
|
/** The merge authority baked into the current session. */
|
|
21979
22190
|
yoloMode = false;
|
|
22191
|
+
/** The live parent-Room reviewer baked into the current session. */
|
|
22192
|
+
reviewerHandle;
|
|
22193
|
+
/** The role-specific second-chance instruction for this session. */
|
|
22194
|
+
cornerTurnEndNudge = CORNER_DELIVERY_NUDGE;
|
|
21980
22195
|
/** Repository state already given a delivery reminder, until that state changes. */
|
|
21981
22196
|
lastDeliveryNudgeState;
|
|
21982
22197
|
turnIdentityInstructions = "";
|
|
@@ -22094,7 +22309,8 @@ var MonolithCornerTurnLoop = class {
|
|
|
22094
22309
|
effort: configuration.effort ?? this.options.config.modelSelection?.effort,
|
|
22095
22310
|
soul: configuration.soul ?? self?.soul,
|
|
22096
22311
|
agentName: self?.name ?? this.agent.name,
|
|
22097
|
-
yoloMode: configuration.yoloMode
|
|
22312
|
+
yoloMode: configuration.yoloMode,
|
|
22313
|
+
reviewerHandle: configuration.reviewerHandle
|
|
22098
22314
|
});
|
|
22099
22315
|
}
|
|
22100
22316
|
async activate(trace) {
|
|
@@ -22114,9 +22330,30 @@ var MonolithCornerTurnLoop = class {
|
|
|
22114
22330
|
effort: configuration.effort ?? this.options.config.modelSelection?.effort,
|
|
22115
22331
|
soul: configuration.soul ?? self?.soul,
|
|
22116
22332
|
agentName: self?.name ?? this.agent.name,
|
|
22117
|
-
yoloMode: configuration.yoloMode
|
|
22333
|
+
yoloMode: configuration.yoloMode,
|
|
22334
|
+
reviewerHandle: configuration.reviewerHandle
|
|
22118
22335
|
});
|
|
22119
22336
|
this.yoloMode = configuration.yoloMode;
|
|
22337
|
+
this.reviewerHandle = configuration.reviewerHandle;
|
|
22338
|
+
const opener = this.options.openedBy ? roster.members.find((member) => member.identityId === this.options.openedBy) : void 0;
|
|
22339
|
+
const reviewerInput = {
|
|
22340
|
+
reviewerHandle: configuration.reviewerHandle,
|
|
22341
|
+
agentHandle: self?.handle,
|
|
22342
|
+
authorHandle: opener?.handle,
|
|
22343
|
+
openedByAgent: !this.options.openedBy || this.options.openedBy === this.agent.publicKey,
|
|
22344
|
+
yoloMode: configuration.yoloMode
|
|
22345
|
+
};
|
|
22346
|
+
let reviewerInstruction = cornerReviewerInstruction(reviewerInput);
|
|
22347
|
+
if (reviewerInstruction) {
|
|
22348
|
+
const restore = await this.options.api.execute("getCornerRestoreState", {
|
|
22349
|
+
cornerId: this.options.cornerId
|
|
22350
|
+
});
|
|
22351
|
+
reviewerInstruction = cornerReviewerInstruction({
|
|
22352
|
+
...reviewerInput,
|
|
22353
|
+
pullRequestNumber: restore.lifecycle?.pr?.number
|
|
22354
|
+
});
|
|
22355
|
+
}
|
|
22356
|
+
this.cornerTurnEndNudge = reviewerInstruction ?? cornerMergeInstruction(configuration.yoloMode, configuration.reviewerHandle);
|
|
22120
22357
|
await mkdir12(this.options.worktreePath, { recursive: true });
|
|
22121
22358
|
const selection = configuration.model || configuration.effort ? { model: configuration.model, effort: configuration.effort } : this.options.config.modelSelection;
|
|
22122
22359
|
const homeOverlay = this.options.config.agentHomeRoot ? await prepareRoomAgentHome({
|
|
@@ -22260,8 +22497,11 @@ var MonolithCornerTurnLoop = class {
|
|
|
22260
22497
|
...repository ? [
|
|
22261
22498
|
`You are in an isolated git worktree on ${repository.featureBranch}, targeting ${repository.targetBranch}.`,
|
|
22262
22499
|
`Commit and push only ${repository.featureBranch}; never force-push or write to ${repository.targetBranch}. Before pushing, rebase on origin/${repository.featureBranch}; resolve conflicts autonomously, realigning to that remote branch and redoing the objective if needed, then rerun affected tests. Open the pull request with gh.`,
|
|
22263
|
-
|
|
22264
|
-
|
|
22500
|
+
...reviewerInstruction ? [reviewerInstruction] : [
|
|
22501
|
+
configuration.reviewerHandle ? `Once the pull request exists, reply with its full URL, then @${configuration.reviewerHandle} please review, and end the turn; do not 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; only a later explicit human resume clears a hold.',
|
|
22502
|
+
CORNER_AUTHOR_CONTRACT,
|
|
22503
|
+
cornerMergeInstruction(configuration.yoloMode, configuration.reviewerHandle)
|
|
22504
|
+
],
|
|
22265
22505
|
"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.",
|
|
22266
22506
|
"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. When approval is pending, wait for the server close request. Never merge another pull request."
|
|
22267
22507
|
] : [
|
|
@@ -22532,12 +22772,12 @@ ${trigger}`,
|
|
|
22532
22772
|
const deliveryState = !checksTurn && this.options.repository ? await cornerUndeliveredRepositoryState(this.options.worktreePath, this.options.repository.featureBranch, this.options.repository.targetBranch) : void 0;
|
|
22533
22773
|
const needsDeliveryNudge = deliveryState !== void 0 && deliveryState !== this.lastDeliveryNudgeState;
|
|
22534
22774
|
let replyBeforeNudge = "";
|
|
22535
|
-
if (!explained && (needsDeliveryNudge || checksTurn && this.yoloMode)) {
|
|
22775
|
+
if (!explained && (needsDeliveryNudge || checksTurn && (this.yoloMode || Boolean(this.reviewerHandle)))) {
|
|
22536
22776
|
if (needsDeliveryNudge)
|
|
22537
22777
|
this.lastDeliveryNudgeState = deliveryState;
|
|
22538
22778
|
replyBeforeNudge = durableReplyText(result.agentText);
|
|
22539
22779
|
await flushToolCalls(result.toolCalls, "");
|
|
22540
|
-
result = await runPrompt(checksTurn ? CORNER_YOLO_MERGE_NUDGE : CORNER_DELIVERY_NUDGE);
|
|
22780
|
+
result = await runPrompt(this.reviewerHandle ? this.cornerTurnEndNudge : checksTurn ? CORNER_YOLO_MERGE_NUDGE : CORNER_DELIVERY_NUDGE);
|
|
22541
22781
|
trace.promptSettled();
|
|
22542
22782
|
explained = await this.explainEmpty(result);
|
|
22543
22783
|
}
|
|
@@ -22589,9 +22829,10 @@ ${trigger}`,
|
|
|
22589
22829
|
requestId,
|
|
22590
22830
|
status: "failed",
|
|
22591
22831
|
generationId: this.commandContext.generationId,
|
|
22592
|
-
reason
|
|
22832
|
+
reason: reason.text,
|
|
22833
|
+
...reason.kind ? { reasonKind: reason.kind } : {}
|
|
22593
22834
|
});
|
|
22594
|
-
await trace.finish("failed", reason);
|
|
22835
|
+
await trace.finish("failed", reason.text);
|
|
22595
22836
|
throw error;
|
|
22596
22837
|
} finally {
|
|
22597
22838
|
this.busy = false;
|
|
@@ -23693,16 +23934,18 @@ var RoomRuntimeCoordinator = class {
|
|
|
23693
23934
|
roomId: cornerId,
|
|
23694
23935
|
limit: 50
|
|
23695
23936
|
});
|
|
23696
|
-
const asked = [...conversation.items].reverse().find((item) => item.type === "message" && item.
|
|
23937
|
+
const asked = [...conversation.items].reverse().find((item) => item.type === "message" && item.authorId !== this.agent.publicKey);
|
|
23697
23938
|
if (!asked)
|
|
23698
23939
|
return;
|
|
23940
|
+
const reason = distillTurnFailureReason(error);
|
|
23699
23941
|
await this.options.daemonApi.execute("postAgentTurnReceipt", {
|
|
23700
23942
|
agentId: this.agent.publicKey,
|
|
23701
23943
|
roomId: cornerId,
|
|
23702
23944
|
requestId: asked.id,
|
|
23703
23945
|
status: "failed",
|
|
23704
23946
|
generationId: `${this.agent.publicKey}:${cornerId}`,
|
|
23705
|
-
reason:
|
|
23947
|
+
reason: reason.text,
|
|
23948
|
+
...reason.kind ? { reasonKind: reason.kind } : {}
|
|
23706
23949
|
});
|
|
23707
23950
|
} catch (reportError) {
|
|
23708
23951
|
console.error(`[thin-core] corner ${cornerId} start-failure report failed:`, reportError);
|
|
@@ -26613,7 +26856,8 @@ async function runStoredDaemon(pathOrPointer) {
|
|
|
26613
26856
|
agentId: runtime.agent.publicKey,
|
|
26614
26857
|
workspaceId: runtime.communityId,
|
|
26615
26858
|
runtimeDir,
|
|
26616
|
-
...runtime.modelSelection ? { runtimeSelection: runtime.modelSelection } : {}
|
|
26859
|
+
...runtime.modelSelection ? { runtimeSelection: runtime.modelSelection } : {},
|
|
26860
|
+
...config.modelUnavailable ? { startupUnavailable: config.modelUnavailable.unavailable.label } : {}
|
|
26617
26861
|
});
|
|
26618
26862
|
},
|
|
26619
26863
|
onProgress: async (status) => {
|