@proagentstore/cli 0.4.104 → 0.4.105
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.
|
@@ -104,6 +104,8 @@ export class HeadlessSession {
|
|
|
104
104
|
turnInputId = null;
|
|
105
105
|
/** Ids of inputs a COMPLETED turn consumed, newest last and bounded (#1019). See {@link consumedInputs}. */
|
|
106
106
|
consumed = [];
|
|
107
|
+
/** Ids of inputs handed to the engine, newest last and bounded (#1019): what a retry is reconciled against. */
|
|
108
|
+
accepted = [];
|
|
107
109
|
/**
|
|
108
110
|
* The engine's own last output line of the turn in flight (#545).
|
|
109
111
|
*
|
|
@@ -321,6 +323,10 @@ export class HeadlessSession {
|
|
|
321
323
|
get consumedInputs() {
|
|
322
324
|
return this.consumed;
|
|
323
325
|
}
|
|
326
|
+
/** Inputs this session accepted — handed to the engine, whether or not a turn has finished on them. */
|
|
327
|
+
get acceptedInputs() {
|
|
328
|
+
return this.accepted;
|
|
329
|
+
}
|
|
324
330
|
credit(id) {
|
|
325
331
|
if (!id)
|
|
326
332
|
return;
|
|
@@ -506,6 +512,11 @@ export class HeadlessSession {
|
|
|
506
512
|
* session-start brief, being the same record composed later.
|
|
507
513
|
*/
|
|
508
514
|
input(text, opts = {}) {
|
|
515
|
+
if (opts.inputId) {
|
|
516
|
+
this.accepted.push(opts.inputId);
|
|
517
|
+
if (this.accepted.length > MAX_CONSUMED_INPUTS)
|
|
518
|
+
this.accepted.shift();
|
|
519
|
+
}
|
|
509
520
|
// The Engine reads the preamble, the pane the short marker; the instruction stays evidence.
|
|
510
521
|
const sent = authoredTurn(text, opts.author);
|
|
511
522
|
// The brief leads the turn and is spent in the reading (#693). It goes to the ENGINE only:
|
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
// The run's objective, delivered verbatim with a turn and attributed to the platform (#1019).
|
|
2
|
+
const ORIGIN_KINDS = new Set(["account", "supervisor", "trigger", "unverified"]);
|
|
2
3
|
/** A run objective as the cloud sent it, or undefined — narrowed, because any caller can POST here (#1019). */
|
|
3
4
|
export function runObjective(raw) {
|
|
4
5
|
const o = raw;
|
|
5
|
-
|
|
6
|
+
if (!(o && typeof o.runId === "string" && o.runId.length <= 128 && typeof o.text === "string" && o.text.trim()))
|
|
7
|
+
return undefined;
|
|
8
|
+
const origin = o.origin;
|
|
9
|
+
const kind = typeof origin?.kind === "string" && ORIGIN_KINDS.has(origin.kind) ? origin.kind : "unverified";
|
|
10
|
+
// A label longer than a label is not shortened into a different claim — it is dropped.
|
|
11
|
+
const label = typeof origin?.by === "string" ? origin.by.replace(/\s+/g, " ").trim() : "";
|
|
12
|
+
const by = label.length <= 128 ? label : "";
|
|
13
|
+
return { runId: o.runId, text: o.text, origin: by ? { kind, by } : { kind } };
|
|
14
|
+
}
|
|
15
|
+
/** The attribution sentence: only what the platform verified about the author, never more. */
|
|
16
|
+
function attribution(runId, origin) {
|
|
17
|
+
const by = origin.by ? ` (${origin.by})` : "";
|
|
18
|
+
switch (origin.kind) {
|
|
19
|
+
case "account":
|
|
20
|
+
return `the objective submitted for run ${runId} through the owner's authenticated account${by}, exactly as ProAgentStore accepted it. Who composed the text is not verified.`;
|
|
21
|
+
case "supervisor":
|
|
22
|
+
return `the objective a supervising agent${by} delegated for run ${runId}, exactly as ProAgentStore accepted it. A supervisor's goal is not an instruction from the owner.`;
|
|
23
|
+
case "trigger":
|
|
24
|
+
return `the objective a trigger${by} composed for run ${runId}, exactly as ProAgentStore accepted it — standing wiring plus facts about another run, not a message from the owner.`;
|
|
25
|
+
default:
|
|
26
|
+
return `the objective ProAgentStore accepted for run ${runId}. Who wrote it is not verified.`;
|
|
27
|
+
}
|
|
6
28
|
}
|
|
7
29
|
/**
|
|
8
|
-
* The run's objective as the engine reads it (#1019): verbatim, fenced,
|
|
9
|
-
* the Pilot's instruction that follows is its own turn, and owner directives sent
|
|
30
|
+
* The run's objective as the engine reads it (#1019): verbatim, fenced, attributed only as far as the
|
|
31
|
+
* platform verified — the Pilot's instruction that follows is its own turn, and owner directives sent
|
|
32
|
+
* later outrank both.
|
|
10
33
|
*/
|
|
11
34
|
export function runObjectiveBlock(o) {
|
|
12
35
|
return [
|
|
13
|
-
`[pags] RUN OBJECTIVE —
|
|
36
|
+
`[pags] RUN OBJECTIVE — ${attribution(o.runId, o.origin ?? { kind: "unverified" })} It is not the Pilot's instruction, which follows as its own turn. Instructions the owner sends later in this run take precedence over it.`,
|
|
14
37
|
"<<<OBJECTIVE",
|
|
15
38
|
o.text,
|
|
16
39
|
"OBJECTIVE>>>",
|
|
@@ -67,8 +67,11 @@ export class CodingRuntime {
|
|
|
67
67
|
// cloud still never trusts it, because an older runner simply 404s and the policy reports
|
|
68
68
|
// that it asked and was not answered.
|
|
69
69
|
// `coding.run-objective` (#1019): a message may carry the run's objective, delivered verbatim and
|
|
70
|
-
// attributed to the platform.
|
|
71
|
-
|
|
70
|
+
// attributed to the platform. `.v2`: attributed by its VERIFIED origin (run-objective.ts) — a cloud
|
|
71
|
+
// sends the objective only to a v2 runner, so an older one is never made to call it the owner's.
|
|
72
|
+
// `coding.input-idempotent`: a message whose inputId this session already accepted is not run again,
|
|
73
|
+
// and every snapshot lists the accepted ids, so a retry after a lost reply can be reconciled.
|
|
74
|
+
return ["coding.sessions", "coding.stream", "human.takeover", "coding.inspect", "coding.repo-write", "coding.run-objective", "coding.run-objective.v2", "coding.input-idempotent"];
|
|
72
75
|
}
|
|
73
76
|
/**
|
|
74
77
|
* Resolve the workDir for a read-only inspection. Prefer the tracked session's real
|
|
@@ -244,6 +247,7 @@ export class CodingRuntime {
|
|
|
244
247
|
// the omitted-when-null shape keeps "not measured" distinguishable from a verdict.
|
|
245
248
|
...(session.lastTurn ? { lastTurn: session.lastTurn } : {}),
|
|
246
249
|
...(session.consumedInputs.length ? { consumedInputs: [...session.consumedInputs] } : {}),
|
|
250
|
+
acceptedInputs: [...session.acceptedInputs],
|
|
247
251
|
...(opts.drainUsage ? { usage: session.takeUsage(), acts: session.takeActs() } : {}),
|
|
248
252
|
};
|
|
249
253
|
}
|
|
@@ -251,16 +255,21 @@ export class CodingRuntime {
|
|
|
251
255
|
act(sessionId, action) {
|
|
252
256
|
const session = this.require(sessionId);
|
|
253
257
|
switch (action.kind) {
|
|
254
|
-
case "message":
|
|
258
|
+
case "message": {
|
|
259
|
+
const inputId = typeof action.inputId === "string" && action.inputId.length <= 128 ? action.inputId : undefined;
|
|
260
|
+
// The same input twice is a retry after a lost reply, not a second instruction (#1019).
|
|
261
|
+
if (inputId && session.acceptedInputs.includes(inputId))
|
|
262
|
+
return { ...this.snapshot(sessionId), duplicateInput: inputId };
|
|
255
263
|
// Narrowed rather than trusted: this runner is a published package any caller can
|
|
256
264
|
// POST to, and an unrecognised author must read as "unstated", not become a label.
|
|
257
265
|
session.input(action.text, {
|
|
258
266
|
author: asTurnAuthor(action.author),
|
|
259
267
|
replay: typeof action.replay === "string" ? action.replay : undefined,
|
|
260
|
-
inputId
|
|
268
|
+
inputId,
|
|
261
269
|
objective: runObjective(action.objective),
|
|
262
270
|
});
|
|
263
271
|
break;
|
|
272
|
+
}
|
|
264
273
|
case "keys": {
|
|
265
274
|
// A snapshot is no longer the whole answer (#448). `key()` records the attempt and
|
|
266
275
|
// reports that it was not delivered; answering 200 with a pane that simply did not
|