@gaunt-sloth/core 2.0.0-beta.0 → 2.0.0-beta.2
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/LICENSE +6 -6
- package/dist/config/loader.d.ts +13 -0
- package/dist/config/loader.js +55 -11
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +10 -0
- package/dist/config/schema.js +46 -24
- package/dist/config/schema.js.map +1 -1
- package/dist/config/shell-policy.d.ts +142 -1
- package/dist/config/shell-policy.js +114 -7
- package/dist/config/shell-policy.js.map +1 -1
- package/dist/config/types.d.ts +19 -0
- package/dist/config/types.js.map +1 -1
- package/dist/constants.d.ts +10 -0
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -1
- package/dist/core/GthAbstractAgent.d.ts +31 -0
- package/dist/core/GthAbstractAgent.js +159 -4
- package/dist/core/GthAbstractAgent.js.map +1 -1
- package/dist/core/GthAgentRunner.d.ts +314 -18
- package/dist/core/GthAgentRunner.js +1032 -101
- package/dist/core/GthAgentRunner.js.map +1 -1
- package/dist/core/approvals/approvalRequest.d.ts +247 -0
- package/dist/core/approvals/approvalRequest.js +315 -0
- package/dist/core/approvals/approvalRequest.js.map +1 -0
- package/dist/core/approvals/grants.d.ts +165 -9
- package/dist/core/approvals/grants.js +702 -57
- package/dist/core/approvals/grants.js.map +1 -1
- package/dist/core/plainToolIndication.d.ts +11 -1
- package/dist/core/plainToolIndication.js +25 -10
- package/dist/core/plainToolIndication.js.map +1 -1
- package/dist/core/shell/abstention.d.ts +1 -1
- package/dist/core/shell/abstention.js +65 -11
- package/dist/core/shell/abstention.js.map +1 -1
- package/dist/core/shell/alignment.d.ts +491 -0
- package/dist/core/shell/alignment.js +687 -0
- package/dist/core/shell/alignment.js.map +1 -0
- package/dist/core/shell/approvalCapture.d.ts +53 -41
- package/dist/core/shell/approvalCapture.js +0 -42
- package/dist/core/shell/approvalCapture.js.map +1 -1
- package/dist/core/shell/approvalStop.d.ts +121 -3
- package/dist/core/shell/approvalStop.js +153 -90
- package/dist/core/shell/approvalStop.js.map +1 -1
- package/dist/core/shell/hardline.d.ts +26 -4
- package/dist/core/shell/hardline.js +321 -16
- package/dist/core/shell/hardline.js.map +1 -1
- package/dist/core/shell/negotiation.d.ts +352 -63
- package/dist/core/shell/negotiation.js +295 -123
- package/dist/core/shell/negotiation.js.map +1 -1
- package/dist/core/shell/openWorld.d.ts +135 -0
- package/dist/core/shell/openWorld.js +572 -35
- package/dist/core/shell/openWorld.js.map +1 -1
- package/dist/core/shell/provenance.d.ts +91 -0
- package/dist/core/shell/provenance.js +136 -0
- package/dist/core/shell/provenance.js.map +1 -0
- package/dist/core/shell/rater.d.ts +394 -163
- package/dist/core/shell/rater.js +536 -238
- package/dist/core/shell/rater.js.map +1 -1
- package/dist/core/shell/raterHealth.d.ts +101 -0
- package/dist/core/shell/raterHealth.js +121 -0
- package/dist/core/shell/raterHealth.js.map +1 -0
- package/dist/core/shell/raterModel.d.ts +17 -8
- package/dist/core/shell/raterModel.js +11 -8
- package/dist/core/shell/raterModel.js.map +1 -1
- package/dist/core/shell/rejection.d.ts +20 -5
- package/dist/core/shell/rejection.js +18 -4
- package/dist/core/shell/rejection.js.map +1 -1
- package/dist/core/toolDisplay.d.ts +42 -0
- package/dist/core/toolDisplay.js +31 -0
- package/dist/core/toolDisplay.js.map +1 -1
- package/dist/core/types.d.ts +134 -16
- package/dist/core/types.js.map +1 -1
- package/dist/providers/configurationPassthrough.d.ts +36 -6
- package/dist/providers/configurationPassthrough.js +40 -28
- package/dist/providers/configurationPassthrough.js.map +1 -1
- package/dist/providers/openrouter.js +36 -6
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/vertexai.js +21 -0
- package/dist/providers/vertexai.js.map +1 -1
- package/dist/utils/binaryOutputUtils.js +103 -21
- package/dist/utils/binaryOutputUtils.js.map +1 -1
- package/dist/utils/fileUtils.d.ts +7 -1
- package/dist/utils/fileUtils.js +17 -3
- package/dist/utils/fileUtils.js.map +1 -1
- package/dist/utils/globalConfigUtils.d.ts +5 -2
- package/dist/utils/globalConfigUtils.js +14 -3
- package/dist/utils/globalConfigUtils.js.map +1 -1
- package/dist/utils/vertexaiUtils.js +61 -3
- package/dist/utils/vertexaiUtils.js.map +1 -1
- package/package.json +4 -4
- package/schema/gsloth-config.schema.json +34 -0
|
@@ -1,30 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module core/shell/negotiation
|
|
3
|
-
*
|
|
4
|
-
* [[EXT-29]] (spec §5) — **the bounded, visible argument between the agent and the rater** that
|
|
5
|
-
* `auto` conducts where `assisted` interrupts a person.
|
|
6
|
-
*
|
|
7
|
-
* A `destructive` rating at `auto` does not go to the human. It goes back to the *agent* as the
|
|
8
|
-
* refused call's tool result (§7), naming what would make the command acceptable (§5.2); the agent
|
|
9
|
-
* may narrow the command or justify the one it chose; the next call is rated again with the
|
|
10
|
-
* exchange in view (§5.1). This module holds the state that makes that a bounded exchange rather
|
|
11
|
-
* than a loop: the transcript, and the two counters that end it at a person.
|
|
12
|
-
*
|
|
13
|
-
* **It decides nothing about safety.** Every round is a full, independent rating by
|
|
14
|
-
* {@link import('./rater.js').mapVerdictToAction}; this only answers *"may another round be
|
|
15
|
-
* served, or is it a human's turn?"*.
|
|
16
|
-
*
|
|
17
|
-
* ## The lifetimes, which are the whole design
|
|
18
|
-
*
|
|
19
|
-
* - **The transcript and the consecutive counter have ONE lifetime, by construction** (§5.3). A
|
|
20
|
-
* successful intervening tool call resets the counter *and clears the transcript with it*, so the
|
|
21
|
-
* rating right after a reset is a round-1 context — the command alone, no transcript and no user
|
|
22
|
-
* messages. They are one field's worth of state precisely because the spec warns that an
|
|
23
|
-
* implementation clearing the counter alone *"looks correct and passes any obvious test"* while
|
|
24
|
-
* letting justification text accumulate across unbounded attempts.
|
|
25
|
-
* - **The reachability bound is monotonic and a reset does not refill it.** See
|
|
26
|
-
* {@link MAX_REJECTIONS_BEFORE_HUMAN}.
|
|
27
|
-
*/
|
|
28
1
|
import { MIN_CONTENT_WIDTH, neutralizeToOneLine, wrapToWidth } from '#src/core/shell/framing.js';
|
|
29
2
|
import { maxDisplayWidth } from '#src/utils/displayWidth.js';
|
|
30
3
|
/**
|
|
@@ -46,10 +19,15 @@ export const MAX_CONSECUTIVE_REJECTIONS = 3;
|
|
|
46
19
|
* add one without a fresh decision. **This is that decision (Andrew, EXT-29), and it answers a
|
|
47
20
|
* different question than the one §5.3 asked.**
|
|
48
21
|
*
|
|
49
|
-
* §5.3's argument is about **safety**, and
|
|
50
|
-
* independently, the rater does not weaken with repetition, and
|
|
51
|
-
*
|
|
52
|
-
*
|
|
22
|
+
* §5.3's argument is about **safety**, and its core is untouched: every attempt is rated
|
|
23
|
+
* independently, the rater does not weaken with repetition, and every deterministic floor is
|
|
24
|
+
* recomputed from the RAW command each round, so no amount of argument unlocks one. What
|
|
25
|
+
* [[EXT-108]] changed is that a reset no longer clears the rounds with the counter, so the
|
|
26
|
+
* justification channel §5.1 opens at round 2 stays open across an approved call — deliberately,
|
|
27
|
+
* because the round after a call the rater itself asked for is the same argument continuing. That
|
|
28
|
+
* is the one channel able to LOWER an outcome, which is why what bounds it matters: this count,
|
|
29
|
+
* which no reset refills, is what ends an argument nobody is winning. Nothing here contradicts
|
|
30
|
+
* §5.3, and this bound must never be described as a security control.
|
|
53
31
|
*
|
|
54
32
|
* The question §5.3 never asked is **reachability**: does the human terminus fire at all? Under its
|
|
55
33
|
* own reset predicate it does not. An agent that alternates one approved `ls` with one rejection
|
|
@@ -92,60 +70,54 @@ export const NEGOTIATION_USER_MESSAGE_RETENTION = 10;
|
|
|
92
70
|
* | event | transcript | consecutive | since-human |
|
|
93
71
|
* |---|---|---|---|
|
|
94
72
|
* | a rejection ({@link recordRejection}) | append | +1 | +1 |
|
|
95
|
-
* | the gate approved a call ({@link noteProgress}) | **
|
|
73
|
+
* | the gate approved a call ({@link noteProgress}) | **kept** | 0 | unchanged |
|
|
96
74
|
* | a human was reached ({@link humanReached}) | cleared | 0 | **0** |
|
|
97
75
|
* | the run halted ({@link humanReached}) | cleared | 0 | 0 |
|
|
98
76
|
*/
|
|
99
77
|
export class ShellNegotiationState {
|
|
100
|
-
/** §5.1's transcript: every round
|
|
78
|
+
/** §5.1's transcript: every round since a person was last involved, oldest first. */
|
|
101
79
|
rounds = [];
|
|
102
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* §5.3's consecutive-rejection count. Reset by an approved call, which [[EXT-108]] stopped taking
|
|
82
|
+
* the rounds with it — so this is the shorter of the two lifetimes, not a shared one.
|
|
83
|
+
*/
|
|
103
84
|
consecutive = 0;
|
|
104
85
|
/** The reachability bound's count. Cleared ONLY by {@link humanReached}. */
|
|
105
86
|
sinceHuman = 0;
|
|
106
87
|
/** §5.1's last user messages, oldest first, capped at {@link NEGOTIATION_USER_MESSAGE_RETENTION}. */
|
|
107
88
|
userMessages = [];
|
|
108
89
|
/**
|
|
109
|
-
* §
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
*
|
|
116
|
-
* An empty negotiation has no privileged spelling on the builder's side, so this always returns an
|
|
117
|
-
* object and never `undefined`: a cleared transcript IS the round-1 case, with no `if` at the call
|
|
118
|
-
* site — which is exactly what makes §5.6's *"a cleared transcript means a round-1 context"* fall
|
|
119
|
-
* out of the reset rather than out of a second branch that could disagree with it.
|
|
120
|
-
*
|
|
121
|
-
* **Everything except the command is admitted from round 2, never at round 1**, and the transcript
|
|
122
|
-
* is what decides which round this is. §5.1 is unambiguous — *"Round 1 sees the command alone —
|
|
123
|
-
* nothing else"* — and §5.6 spells out the consequence for the round right after a reset: *"the
|
|
124
|
-
* command and nothing else — no transcript, no user messages, because that is what round 1 means"*.
|
|
90
|
+
* [[EXT-106]] §4.6 — whether {@link retainedUserMessages} may hand this session's human turns out
|
|
91
|
+
* as **the user's own words**. See {@link admitUserProvenance}; `false` until something positively
|
|
92
|
+
* establishes otherwise, which is the whole of its safety.
|
|
93
|
+
*/
|
|
94
|
+
userProvenanceAdmitted = false;
|
|
95
|
+
/**
|
|
96
|
+
* [[EXT-127]] — **the checker's own earlier rounds, for the alignment check about to be made.**
|
|
125
97
|
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* for the agent or for anything that has injected into the agent's context. Withholding it until
|
|
132
|
-
* round 2 is what the spec's ordering buys, and a round-1 context is byte-identical to a plain
|
|
133
|
-
* rating because of it.
|
|
98
|
+
* The rounds it returns are the transcript's, with each round's alignment decision attached where
|
|
99
|
+
* the checker made one. What §5.1's withholding rules used to govern here is gone with the flat
|
|
100
|
+
* context they governed: the classifier now sees the command alone at every round, and the
|
|
101
|
+
* checker's context is assembled across message roles by
|
|
102
|
+
* {@link import('./alignment.js').buildAlignmentMessages} rather than handed over as a block.
|
|
134
103
|
*
|
|
135
|
-
* The
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
* it arriving on. A justification the agent supplies again with its next attempt is admitted then,
|
|
140
|
-
* because by then there is a rejection for it to answer.
|
|
104
|
+
* **The user's words are deliberately NOT here.** They come from
|
|
105
|
+
* {@link retainedUserMessages} — the gated provenance channel — and never from this method or
|
|
106
|
+
* from {@link noteUserMessages}' store. Routing them through a "context for the next call"
|
|
107
|
+
* accessor is exactly how the gate would come to be bypassed by a caller doing the obvious thing.
|
|
141
108
|
*/
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
109
|
+
alignmentRounds() {
|
|
110
|
+
return this.rounds
|
|
111
|
+
.filter((round) => round.alignment !== undefined)
|
|
112
|
+
.map((round) => ({
|
|
113
|
+
subject: {
|
|
114
|
+
command: round.command,
|
|
115
|
+
outcome: round.outcome,
|
|
116
|
+
reason: round.reason,
|
|
117
|
+
...(round.justification ? { justification: round.justification } : {}),
|
|
118
|
+
},
|
|
119
|
+
decision: round.alignment,
|
|
120
|
+
}));
|
|
149
121
|
}
|
|
150
122
|
/**
|
|
151
123
|
* Record a rejected round and decide whether another may be served.
|
|
@@ -167,16 +139,24 @@ export class ShellNegotiationState {
|
|
|
167
139
|
return 'reject';
|
|
168
140
|
}
|
|
169
141
|
/**
|
|
170
|
-
* §5.3 — a tool call the gate let through. Resets the consecutive counter
|
|
171
|
-
*
|
|
142
|
+
* §5.3 — a tool call the gate let through. Resets the consecutive counter and **nothing else**:
|
|
143
|
+
* the rounds stand, and so does the reachability bound.
|
|
144
|
+
*
|
|
145
|
+
* **The counter reset is §5.3's and is sound; taking the rounds with it was not** ([[EXT-108]]).
|
|
146
|
+
* The reset exists to bound a *stalled* negotiation — an agent that went away, gathered
|
|
147
|
+
* information and came back better informed is making progress, not ping-pong. But the approved
|
|
148
|
+
* call is very often the agent doing exactly what the rejection told it to do, and clearing the
|
|
149
|
+
* rounds there makes that compliance erase the record of the advice: the retry is then rated with
|
|
150
|
+
* an empty transcript, which {@link contextFor} correctly reads as round 1 and so withholds the
|
|
151
|
+
* justification and the user messages from. **Measured**: the rater refused `git reset --hard`
|
|
152
|
+
* advising a stash first, the agent stashed, and the rater then advised a stash twice more —
|
|
153
|
+
* recommending a thing already done, because on the evidence it was given it could not know.
|
|
172
154
|
*
|
|
173
|
-
* **What
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* itself survives whole in [[TUI-C27]]'s archive, which captures per RATING CALL and so is not
|
|
179
|
-
* truncated by anything here.
|
|
155
|
+
* **What replaces the clearing as a bound is the count this deliberately leaves standing.** Every
|
|
156
|
+
* appended round increments {@link NegotiationCounters.rejectionsSinceHuman}, which no reset
|
|
157
|
+
* refills, so a transcript still cannot grow past {@link MAX_REJECTIONS_BEFORE_HUMAN} rounds
|
|
158
|
+
* before {@link humanReached} clears the lot. A cap on the retained rounds would bound something
|
|
159
|
+
* that is already bounded, and would re-introduce the erasure on a longer fuse.
|
|
180
160
|
*
|
|
181
161
|
* **"Approved" is what the gate can observe, and it is not quite §5.3's "successful".** The
|
|
182
162
|
* decision site sees whether a call was allowed to run, never whether it then exited zero — and
|
|
@@ -186,7 +166,6 @@ export class ShellNegotiationState {
|
|
|
186
166
|
* {@link MAX_REJECTIONS_BEFORE_HUMAN} is monotonic for.
|
|
187
167
|
*/
|
|
188
168
|
noteProgress() {
|
|
189
|
-
this.rounds = [];
|
|
190
169
|
this.consecutive = 0;
|
|
191
170
|
}
|
|
192
171
|
/**
|
|
@@ -228,6 +207,54 @@ export class ShellNegotiationState {
|
|
|
228
207
|
this.userMessages = this.userMessages.slice(-NEGOTIATION_USER_MESSAGE_RETENTION);
|
|
229
208
|
}
|
|
230
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* [[EXT-106]] §4.6 — **the user's own words, for the provenance carve-out that lifts the
|
|
212
|
+
* open-world floor.** A snapshot, oldest first, of the whole retained window.
|
|
213
|
+
*
|
|
214
|
+
* **This is deliberately NOT {@link contextFor}, and the difference is the point.** That function
|
|
215
|
+
* returns `userMessages: []` at round 1 by design — §5.1's *"round 1 sees the command alone"* —
|
|
216
|
+
* and round 1 is exactly the round the carve-out exists to act on: the user asks for a fetch, the
|
|
217
|
+
* agent proposes it, and there has been no rejection for a round 2 to exist. §5.1 bounds what the
|
|
218
|
+
* **rater** may see, and the floor is not the rater. Reading `contextFor()` here would make the
|
|
219
|
+
* carve-out fire only after the command had already been refused once, i.e. never in the case it
|
|
220
|
+
* was built for.
|
|
221
|
+
*
|
|
222
|
+
* The window is cumulative across the turns of a thread (capped and de-duplicated by
|
|
223
|
+
* {@link noteUserMessages}), so a host named in an earlier turn still carves a command proposed in
|
|
224
|
+
* a later one. {@link clear} drops it with the thread.
|
|
225
|
+
*
|
|
226
|
+
* **Empty until {@link admitUserProvenance} says otherwise**, which is why this is the provenance
|
|
227
|
+
* window rather than {@link noteUserMessages}'s store: the store also feeds §5.1's negotiation
|
|
228
|
+
* context, a different question with a different reader, and one that a command's fetched content
|
|
229
|
+
* is legitimately part of. What must never be answered *"yes, the human said this"* is this
|
|
230
|
+
* accessor, so the gate lives on it and defaults to refusing.
|
|
231
|
+
*/
|
|
232
|
+
retainedUserMessages() {
|
|
233
|
+
if (!this.userProvenanceAdmitted)
|
|
234
|
+
return [];
|
|
235
|
+
return [...this.userMessages];
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* [[EXT-106]] §4.6 — **declare whether this session's human turns are the user's own words**, and
|
|
239
|
+
* therefore whether {@link retainedUserMessages} may return them at all.
|
|
240
|
+
*
|
|
241
|
+
* A human message the product SYNTHESISED from content it fetched must never enter the provenance
|
|
242
|
+
* window: `review` and `pr` hand the agent a diff and a PR description that gaunt-sloth went and
|
|
243
|
+
* got, and the review prompt tells the agent to examine them. Reading the same bytes as the user's
|
|
244
|
+
* verbatim words would make the product contradict itself about identical input — and the words
|
|
245
|
+
* are written by whoever opened the pull request.
|
|
246
|
+
*
|
|
247
|
+
* **It defaults to `false` and the caller must positively establish otherwise**, so a surface that
|
|
248
|
+
* never calls this — or a future driver nobody has classified — floors exactly as it did before
|
|
249
|
+
* the carve-out existed. The one caller is
|
|
250
|
+
* {@link import('../GthAgentRunner.js').GthAgentRunner.init}, which decides it from the CLI verb
|
|
251
|
+
* ({@link import('../../config/shell-policy.js').commandCarriesUserProvenance}) and never from
|
|
252
|
+
* anything inside a message: those bytes are attacker-controlled, so a marker in them can be
|
|
253
|
+
* forged by the text it is supposed to classify.
|
|
254
|
+
*/
|
|
255
|
+
admitUserProvenance(admitted) {
|
|
256
|
+
this.userProvenanceAdmitted = admitted;
|
|
257
|
+
}
|
|
231
258
|
/**
|
|
232
259
|
* §6 — the rounds to show the human, oldest first. A snapshot: the caller holds it across the
|
|
233
260
|
* {@link humanReached} that immediately follows, and nothing it holds may change underneath it.
|
|
@@ -264,6 +291,26 @@ export class ShellNegotiationState {
|
|
|
264
291
|
this.userMessages = [];
|
|
265
292
|
}
|
|
266
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* §5.5 — **the minimum interval a negotiated approval is visible before it takes effect.**
|
|
296
|
+
*
|
|
297
|
+
* It must never be described or relied upon as an opportunity to evaluate the command: nobody
|
|
298
|
+
* reads a command in 800 ms, and a design that assumed they did would be resting a safety property
|
|
299
|
+
* on a glance. What it buys is that the approving round exists on screen as its own event, rather
|
|
300
|
+
* than being drawn and overwritten by the tool's own output in the same frame.
|
|
301
|
+
*
|
|
302
|
+
* **It is NOT a guaranteed abort window on either surface**, and the claim must not be restored
|
|
303
|
+
* without the mechanism: on the event/TUI path an abort during the interval does stop the tool,
|
|
304
|
+
* but because LangGraph refuses an already-aborted signal rather than because this code re-checks
|
|
305
|
+
* one; on the plain/readline path no signal is threaded and the Esc handler is torn down before
|
|
306
|
+
* the interval begins, so the command runs. See `GthAgentRunner.showNegotiatedApproval`, which
|
|
307
|
+
* carries the full statement of what is true where.
|
|
308
|
+
*
|
|
309
|
+
* **A minimum visible interval, not a delay added to a finished decision.** The real window is
|
|
310
|
+
* longer at both ends — the rater call's own latency precedes it, and the tool takes time to start
|
|
311
|
+
* after it — so this bounds the short end of a window that mostly already exists.
|
|
312
|
+
*/
|
|
313
|
+
export const NEGOTIATED_APPROVAL_COOLDOWN_MS = 800;
|
|
267
314
|
/**
|
|
268
315
|
* The prefix a row too wide for the terminal is continued with.
|
|
269
316
|
*
|
|
@@ -282,10 +329,10 @@ const CONTINUATION_PREFIX = ' ┊ ';
|
|
|
282
329
|
* **MEASURED, and it is the height bound this block needs rather than a cap on rounds.** At 80
|
|
283
330
|
* columns three rounds of paragraph-length argument cost 37 rows, of which one round was 12; the
|
|
284
331
|
* whole prompt was 64 rows against a 20-row budget, so the human saw the command and the verdict
|
|
285
|
-
* and neither the later rounds nor the menu line. A cap on the NUMBER of rounds
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
* element keeps every round structurally on the screen, which is what §5.6 calls the most important
|
|
332
|
+
* and neither the later rounds nor the menu line. A cap on the NUMBER of rounds does not answer
|
|
333
|
+
* that — the measured case was three rounds, exactly what {@link NEGOTIATION_MAX_ROUNDS_SHOWN}
|
|
334
|
+
* allows a screen, and it still cost 37 rows — because the cost is per row, not per round. Bounding
|
|
335
|
+
* each element keeps every round structurally on the screen, which is what §5.6 calls the most important
|
|
289
336
|
* thing on it, and pays for it out of the tail of a paragraph the reader was never going to need in
|
|
290
337
|
* full: the archive keeps every round whole ([[TUI-C27]]'s capture is per rating call).
|
|
291
338
|
*
|
|
@@ -294,10 +341,12 @@ const CONTINUATION_PREFIX = ' ┊ ';
|
|
|
294
341
|
*/
|
|
295
342
|
export const NEGOTIATION_MAX_ROWS_PER_ELEMENT = 2;
|
|
296
343
|
/**
|
|
297
|
-
* Rounds a screen shows, newest last.
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
344
|
+
* Rounds a screen shows, newest last. **Binding rather than a backstop, since [[EXT-108]]**: an
|
|
345
|
+
* approved call no longer clears the transcript, so an agent that makes progress between refusals
|
|
346
|
+
* reaches a person carrying every round since the last one — up to
|
|
347
|
+
* {@link MAX_REJECTIONS_BEFORE_HUMAN} of them — and an unscrollable prompt cannot grow a section
|
|
348
|
+
* that long. What is dropped is said out loud in the heading, which carries the true count, and the
|
|
349
|
+
* markers keyed on a position in the transcript stay keyed on it across the slice.
|
|
301
350
|
*/
|
|
302
351
|
export const NEGOTIATION_MAX_ROUNDS_SHOWN = 3;
|
|
303
352
|
/**
|
|
@@ -329,18 +378,21 @@ export const NEGOTIATION_MAX_ROUNDS_SHOWN = 3;
|
|
|
329
378
|
* and each of these lied toward approving, at the moment a human was deciding whether to overrule
|
|
330
379
|
* a refusal.
|
|
331
380
|
*
|
|
332
|
-
* - **`attempts`
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
*
|
|
381
|
+
* - **`attempts` counts the argument; the rounds below it are a slice of that argument.** A screen
|
|
382
|
+
* shows at most {@link NEGOTIATION_MAX_ROUNDS_SHOWN} of them, so the heading has to report what
|
|
383
|
+
* happened rather than what fits, and the rounds have to be numbered from the true attempt
|
|
384
|
+
* number. The caller's `rejectionsSinceHuman` is that count. [[EXT-108]] brought it into
|
|
385
|
+
* agreement with `rounds.length` for a caller holding the whole transcript — an approved call no
|
|
386
|
+
* longer erases rounds, and one event clears both — so what this parameter still guards is the
|
|
387
|
+
* slice, plus the `Math.max` below, which stops a stale or smaller number making the block claim
|
|
388
|
+
* less argument than it is about to print. Omit it and this falls back to `rounds.length`, the
|
|
389
|
+
* honest reading of a caller that has no better number.
|
|
338
390
|
* - **The last round IS the pending rating, not a prior one.** {@link
|
|
339
391
|
* ShellNegotiationState.recordRejection} appends before either bound is tested, deliberately, so
|
|
340
392
|
* that the rating being escalated is on the transcript the human sees. The old heading called
|
|
341
393
|
* them all prior rounds, which both under-reported the argument and put the pending command on
|
|
342
394
|
* the screen twice with nothing saying they were the same call.
|
|
343
|
-
* - **The first round was rated on the command alone.**
|
|
395
|
+
* - **The first round was rated on the command alone.** An EMPTY transcript IS the round-1 case
|
|
344
396
|
* (see {@link ShellNegotiationState.contextFor}), so §5.1 withheld the justification and the user
|
|
345
397
|
* messages from that rating — while {@link ShellNegotiationState.recordRejection} stores the
|
|
346
398
|
* justification the agent supplied whatever the round. Printed unmarked, the round reads as a
|
|
@@ -359,54 +411,174 @@ export function renderNegotiationRows(rounds, options) {
|
|
|
359
411
|
if (rounds.length === 0)
|
|
360
412
|
return [];
|
|
361
413
|
const width = options?.width;
|
|
414
|
+
const live = options?.mode === 'live';
|
|
415
|
+
// The rater agreeing ends the argument; it is not another numbered attempt in it. Only a live
|
|
416
|
+
// block can carry one — the escalation block renders the transcript, and the transcript holds
|
|
417
|
+
// rejections alone.
|
|
418
|
+
const agreed = live && options?.agreed === true;
|
|
362
419
|
// A screen shows the newest rounds; a consumer with no screen (§6.2's exception message) shows
|
|
363
420
|
// them all, for the same reason it is handed no width.
|
|
364
421
|
const shown = width === undefined ? rounds : rounds.slice(-NEGOTIATION_MAX_ROUNDS_SHOWN);
|
|
365
422
|
// Never fewer attempts than rounds on the screen: a caller that passes a stale or smaller number
|
|
366
423
|
// must not be able to make this block claim less argument than it is about to print.
|
|
367
424
|
const attempts = Math.max(options?.attempts ?? rounds.length, rounds.length);
|
|
425
|
+
// How many of the transcript's own rounds precede the first one shown, so a marker keyed on a
|
|
426
|
+
// POSITION IN THE TRANSCRIPT (round one, the pending round) stays keyed on it after the slice.
|
|
427
|
+
// A caller that took its own slice says so; otherwise this block took it and knows.
|
|
428
|
+
const dropped = options?.from ?? rounds.length - shown.length;
|
|
368
429
|
// The shown rounds are the most recent ones, so they are attempts `attempts - shown + 1` … N.
|
|
369
430
|
// Numbering them by their true attempt number is what stops the heading's count and the rounds
|
|
370
|
-
// beneath it describing two different exchanges.
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
{
|
|
431
|
+
// beneath it describing two different exchanges. A live block has no such heading to agree with
|
|
432
|
+
// and knows exactly where its round sits, so it numbers from the position itself.
|
|
433
|
+
const firstNumber = live ? dropped + 1 : attempts - shown.length + 1;
|
|
434
|
+
const rows = [];
|
|
435
|
+
if (!live) {
|
|
436
|
+
rows.push({
|
|
377
437
|
voice: 'chrome',
|
|
378
438
|
text: attempts > shown.length
|
|
379
439
|
? `The agent argued with the auto-rater ${attempts} times; the last ${shown.length} of them:`
|
|
380
440
|
: `The agent argued with the auto-rater ${attempts} ${attempts === 1 ? 'time' : 'times'}:`,
|
|
381
|
-
}
|
|
382
|
-
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
else if (dropped === 0) {
|
|
444
|
+
// §5.4 — one context sentence per exchange, over the round that opens it. Repeating it on
|
|
445
|
+
// every round would spend a row per round saying the same thing, and saying nothing at all
|
|
446
|
+
// leaves a bare `Round 1:` with no account of what is talking to what.
|
|
447
|
+
rows.push({ voice: 'chrome', text: 'The agent is negotiating with the auto-rater:' });
|
|
448
|
+
}
|
|
383
449
|
shown.forEach((round, index) => {
|
|
384
450
|
// **Each marker rides the row whose reading it corrects, and no other.** Put on the `Round`
|
|
385
451
|
// row they would be paid for in the one thing that row is for — the command, and how it
|
|
386
452
|
// compares with the round above it — which at a narrow width is most of what fits on it.
|
|
387
|
-
|
|
388
|
-
//
|
|
453
|
+
//
|
|
454
|
+
// §5.4 — a LIVE round is never the pending request: nothing is being ruled on yet, and the
|
|
455
|
+
// marker means *this is the call you are being asked about*.
|
|
456
|
+
const pending = !live && dropped + index === rounds.length - 1 ? ' (this request)' : '';
|
|
457
|
+
// **The round that ENDS the argument is labelled, not numbered.** Numbering it would spend a
|
|
458
|
+
// number the transcript is about to reuse — the approved call never joins the transcript, so
|
|
459
|
+
// the next rejection sits at the very position this round was drawn at, and the escalation
|
|
460
|
+
// prompt then gives that number to a third command. A label cannot collide with a count.
|
|
461
|
+
rows.push(...negotiationRoundRows(round, agreed ? endingLabel(options?.revised) : `Round ${firstNumber + index}${pending}`,
|
|
462
|
+
// An EMPTY transcript IS the round-1 case, so the transcript's FIRST round is the one §5.1
|
|
389
463
|
// rated on the command alone. Derived from the position rather than carried on the round
|
|
390
|
-
// because it is a property of the transcript, not of the rating
|
|
391
|
-
//
|
|
392
|
-
|
|
464
|
+
// because it is a property of the transcript, not of the rating.
|
|
465
|
+
//
|
|
466
|
+
// An `agreed` round is never it, and that is a fact about the transcript rather than about
|
|
467
|
+
// today's call sites: the approved call is not ON the transcript, so it cannot be the first
|
|
468
|
+
// thing on it whatever position it is drawn at. Said here rather than left to the caller's
|
|
469
|
+
// arithmetic so no future emitter can make the §5.1 marker lie by drawing an agreement at
|
|
470
|
+
// position zero.
|
|
471
|
+
!agreed && dropped + index === 0));
|
|
472
|
+
});
|
|
473
|
+
if (width === undefined)
|
|
474
|
+
return rows;
|
|
475
|
+
return rows.flatMap((row) => wrapRow(row, width));
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* [[TUI-C69]] §5.4 — the label over the round that ENDS an argument, in the one place both the live
|
|
479
|
+
* list and the single-round live render read it from, so the two surfaces cannot say different
|
|
480
|
+
* things about the same event.
|
|
481
|
+
*
|
|
482
|
+
* *Agreed* is a claim about the rater's opinion of THIS command; *Accepted* is a claim only about
|
|
483
|
+
* what it let through. Using the first where the second is true prints a false statement about the
|
|
484
|
+
* auto-rater, which is worse than the vaguer word.
|
|
485
|
+
*/
|
|
486
|
+
const endingLabel = (revised) => revised === true ? 'Accepted' : 'Agreed';
|
|
487
|
+
/**
|
|
488
|
+
* The three rows one round of the argument occupies — the command, the agent's justification if it
|
|
489
|
+
* gave one, and the rater's answer — with the label already decided by the caller.
|
|
490
|
+
*
|
|
491
|
+
* **Extracted so the live panel and the escalation prompt cannot drift.** They differ in what they
|
|
492
|
+
* put ABOVE the rounds (a heading, a context sentence) and in how many rounds they show; they must
|
|
493
|
+
* not differ by so much as a colon in the rounds themselves, because the whole claim §5.4 rests on
|
|
494
|
+
* is that the exchange a person watched and the exchange they are later asked to rule on are one
|
|
495
|
+
* account of one argument. Two copies of this body is precisely how that claim would rot.
|
|
496
|
+
*
|
|
497
|
+
* ---
|
|
498
|
+
*
|
|
499
|
+
* [[EXT-127]] — **the two speaker-named rows below stay exactly as they are, and this is the
|
|
500
|
+
* recorded decision rather than an omission.** The node that split the gate in two asks deliberately
|
|
501
|
+
* whether rows saying `rater` should move now that there are two models, and the answer is no, for a
|
|
502
|
+
* reason that is about truth rather than effort:
|
|
503
|
+
*
|
|
504
|
+
* - every row here renders the CLASSIFIER's own verdict — `round.outcome` and `round.reason` are its
|
|
505
|
+
* answer, and it is still the auto-rater. Nothing on these rows was ever the alignment checker's,
|
|
506
|
+
* so nothing here is misattributed;
|
|
507
|
+
* - `(not shown to the rater)` and `(on the command alone)` are MORE literally true after the split
|
|
508
|
+
* than before it, because the classifier's input shrank to the command. Rewording either one to
|
|
509
|
+
* account for the checker would make a true statement about the classifier into a false one;
|
|
510
|
+
* - the checker's own voice on screen is an ADDITION to the display, not a correction of it — a new
|
|
511
|
+
* row for a new speaker. That is display work in its own right (the [[TUI-C69]]/[[TUI-C98]]
|
|
512
|
+
* surface), it moves strings the `tui-e2e` suite asserts on by literal, and it therefore needs the
|
|
513
|
+
* Windows cell of `tui-e2e.yml` read before it lands. It is deliberately NOT done here.
|
|
514
|
+
*
|
|
515
|
+
* So: the existing labels are SETTLED and must not be reworded. Showing the check's own answer is
|
|
516
|
+
* DEFERRED, and is a display ticket, not a leftover of this one.
|
|
517
|
+
*/
|
|
518
|
+
function negotiationRoundRows(round, label, roundOne) {
|
|
519
|
+
const rows = [
|
|
520
|
+
{ voice: 'agent', text: ` ${label}: ${oneLine(round.command)}` },
|
|
521
|
+
];
|
|
522
|
+
const justification = round.justification?.trim();
|
|
523
|
+
if (justification) {
|
|
393
524
|
rows.push({
|
|
394
525
|
voice: 'agent',
|
|
395
|
-
text: `
|
|
396
|
-
});
|
|
397
|
-
const justification = round.justification?.trim();
|
|
398
|
-
if (justification) {
|
|
399
|
-
rows.push({
|
|
400
|
-
voice: 'agent',
|
|
401
|
-
text: ` agent justified${roundOne ? ' (not shown to the rater)' : ''}: ${oneLine(justification)}`,
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
const reason = round.reason.trim();
|
|
405
|
-
rows.push({
|
|
406
|
-
voice: 'rater',
|
|
407
|
-
text: ` rater answered${roundOne ? ' (on the command alone)' : ''}: ${round.outcome}${reason ? ` — ${oneLine(reason)}` : ''}`,
|
|
526
|
+
text: ` agent justified${roundOne ? ' (not shown to the rater)' : ''}: ${oneLine(justification)}`,
|
|
408
527
|
});
|
|
528
|
+
}
|
|
529
|
+
const reason = round.reason.trim();
|
|
530
|
+
rows.push({
|
|
531
|
+
voice: 'rater',
|
|
532
|
+
text: ` rater answered${roundOne ? ' (on the command alone)' : ''}: ${round.outcome}${reason ? ` — ${oneLine(reason)}` : ''}`,
|
|
409
533
|
});
|
|
534
|
+
return rows;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* [[TUI-C69]] §5.4 — **the whole live exchange as a bounded screen**, for a surface that redraws a
|
|
538
|
+
* pinned region rather than appending to scrollback.
|
|
539
|
+
*
|
|
540
|
+
* ## Why this exists rather than the caller looping over {@link renderNegotiationRows}
|
|
541
|
+
*
|
|
542
|
+
* **A cap applied one round at a time is not a cap.** The escalation prompt hands the renderer its
|
|
543
|
+
* whole transcript, so `slice(-NEGOTIATION_MAX_ROUNDS_SHOWN)` bounds it; a live surface that
|
|
544
|
+
* rendered each round as it arrived and kept the output handed the renderer a ONE-element array
|
|
545
|
+
* every time, where that slice is an identity operation, and then accumulated the results. The
|
|
546
|
+
* bound was still in the code and applied to nothing. **Measured**: a nine-round argument cost 46
|
|
547
|
+
* rows at 80 columns that way, against 16 for the same argument in the prompt.
|
|
548
|
+
*
|
|
549
|
+
* That is not a tidiness problem. The Ink surface pins this inside a `flexShrink={0}` dock —
|
|
550
|
+
* [[TUI-C75]]'s governing constraint is that the dialog does not scroll, so rows spent here are
|
|
551
|
+
* taken from the conversation, and past a couple of dozen they push the input prompt off the
|
|
552
|
+
* bottom of an 80×24 terminal. Every other occupant of that dock is bounded; this was the one that
|
|
553
|
+
* was not.
|
|
554
|
+
*
|
|
555
|
+
* ## What it shows
|
|
556
|
+
*
|
|
557
|
+
* The newest {@link NEGOTIATION_MAX_ROUNDS_SHOWN} rounds, **unconditionally** — a screen is what
|
|
558
|
+
* this is for, so unlike {@link renderNegotiationRows} it does not let an absent `width` mean "show
|
|
559
|
+
* everything". A caller that wants the whole exchange unbounded wants the escalation renderer.
|
|
560
|
+
*
|
|
561
|
+
* Each round keeps the number of its own position in the transcript, so the numbers a watcher sees
|
|
562
|
+
* are the numbers the escalation prompt will use for the same rounds even after the earlier ones
|
|
563
|
+
* scroll out of this window — and an `agreed` round is labelled rather than numbered, for the
|
|
564
|
+
* reason {@link LiveNegotiationRound.agreed} gives.
|
|
565
|
+
*
|
|
566
|
+
* The context sentence is drawn **every time** rather than only over round one. Once the window
|
|
567
|
+
* slides, the round that carried it is gone, and the alternative is a bare `Round 7:` heading
|
|
568
|
+
* nothing — an unattributed command sitting in the chrome of a tool that is asking the user to
|
|
569
|
+
* trust it. One row is the right price for saying whose argument this is.
|
|
570
|
+
*/
|
|
571
|
+
export function renderLiveNegotiationRows(rounds, options) {
|
|
572
|
+
if (rounds.length === 0)
|
|
573
|
+
return [];
|
|
574
|
+
const width = options?.width;
|
|
575
|
+
const shown = rounds.slice(-NEGOTIATION_MAX_ROUNDS_SHOWN);
|
|
576
|
+
const rows = [
|
|
577
|
+
{ voice: 'chrome', text: 'The agent is negotiating with the auto-rater:' },
|
|
578
|
+
];
|
|
579
|
+
for (const entry of shown) {
|
|
580
|
+
rows.push(...negotiationRoundRows(entry.round, entry.agreed === true ? endingLabel(entry.revised) : `Round ${entry.position + 1}`, entry.agreed !== true && entry.position === 0));
|
|
581
|
+
}
|
|
410
582
|
if (width === undefined)
|
|
411
583
|
return rows;
|
|
412
584
|
return rows.flatMap((row) => wrapRow(row, width));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"negotiation.js","sourceRoot":"","sources":["../../../src/core/shell/negotiation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"negotiation.js","sourceRoot":"","sources":["../../../src/core/shell/negotiation.ts"],"names":[],"mappings":"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"}
|