@corenel/harness 0.5.0 → 0.5.1
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/api/backend.d.ts +24 -0
- package/dist/api/backend.d.ts.map +1 -1
- package/dist/api/backend.js +32 -8
- package/dist/api/backend.js.map +1 -1
- package/dist/rooms/findings.d.ts +134 -0
- package/dist/rooms/findings.d.ts.map +1 -0
- package/dist/rooms/findings.js +262 -0
- package/dist/rooms/findings.js.map +1 -0
- package/dist/sidecar/host.d.ts +115 -4
- package/dist/sidecar/host.d.ts.map +1 -1
- package/dist/sidecar/host.js +239 -3
- package/dist/sidecar/host.js.map +1 -1
- package/dist/sidecar/server.d.ts +136 -2
- package/dist/sidecar/server.d.ts.map +1 -1
- package/dist/sidecar/server.js +313 -2
- package/dist/sidecar/server.js.map +1 -1
- package/dist/tools/builtins.d.ts.map +1 -1
- package/dist/tools/builtins.js +8 -0
- package/dist/tools/builtins.js.map +1 -1
- package/dist/tools/files.d.ts.map +1 -1
- package/dist/tools/files.js +8 -0
- package/dist/tools/files.js.map +1 -1
- package/dist/tools/roomTools.d.ts +68 -5
- package/dist/tools/roomTools.d.ts.map +1 -1
- package/dist/tools/roomTools.js +210 -19
- package/dist/tools/roomTools.js.map +1 -1
- package/dist/tools/sessions.d.ts.map +1 -1
- package/dist/tools/sessions.js +1 -0
- package/dist/tools/sessions.js.map +1 -1
- package/dist/tools/web.d.ts.map +1 -1
- package/dist/tools/web.js +3 -0
- package/dist/tools/web.js.map +1 -1
- package/package.json +6 -1
package/dist/api/backend.d.ts
CHANGED
|
@@ -12,6 +12,27 @@ export interface BackendConfig {
|
|
|
12
12
|
/** Injected so a test needs no network; defaults to the ambient fetch. */
|
|
13
13
|
fetch?: typeof fetch;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* What the probe found -- INCLUDING whether it got an answer at all.
|
|
17
|
+
*
|
|
18
|
+
* An empty capability list has two completely different meanings, and reading
|
|
19
|
+
* them as one is what hid a probe asking the wrong path for as long as the
|
|
20
|
+
* feature existed: a backend that ANSWERS without `sessions` is a normal thing
|
|
21
|
+
* to be pointed at (prompd's gateway only runs models), while a 404, a timeout
|
|
22
|
+
* or an HTML error page means the question was never answered. The first is
|
|
23
|
+
* settled; the second is a URL to check. `url` is carried so whoever reports it
|
|
24
|
+
* can name what was asked.
|
|
25
|
+
*/
|
|
26
|
+
export interface ProbeOutcome {
|
|
27
|
+
/** The URL the probe asked. */
|
|
28
|
+
url: string;
|
|
29
|
+
/** True only when the backend replied with JSON we could read. */
|
|
30
|
+
answered: boolean;
|
|
31
|
+
/** What it said it can do. Empty and `answered` is a real "no". */
|
|
32
|
+
capabilities: readonly string[];
|
|
33
|
+
/** Why it did not answer. Absent when it did. */
|
|
34
|
+
reason?: string;
|
|
35
|
+
}
|
|
15
36
|
export interface Backend {
|
|
16
37
|
readonly baseUrl: string;
|
|
17
38
|
readonly client: CorenelApiClient;
|
|
@@ -21,6 +42,9 @@ export interface Backend {
|
|
|
21
42
|
supports(capability: string): boolean;
|
|
22
43
|
/** Ask the backend what it is. Safe to call more than once. */
|
|
23
44
|
probe(): Promise<readonly string[]>;
|
|
45
|
+
/** The same question, with whether it was answered at all. Prefer this
|
|
46
|
+
* anywhere the result is REPORTED to a person. */
|
|
47
|
+
probeDetail(): Promise<ProbeOutcome>;
|
|
24
48
|
}
|
|
25
49
|
/**
|
|
26
50
|
* Point at a backend, or at none.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../api/backend.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AAE/D;;eAEe;AACf,eAAO,MAAM,YAAY,aAAa,CAAC;AACvC,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IACrC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC;4CACwC;IACxC,YAAY,IAAI,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACtC,+DAA+D;IAC/D,KAAK,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../api/backend.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AAE/D;;eAEe;AACf,eAAO,MAAM,YAAY,aAAa,CAAC;AACvC,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IACrC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC;4CACwC;IACxC,YAAY,IAAI,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACtC,+DAA+D;IAC/D,KAAK,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACpC;sDACkD;IAClD,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;CACtC;AA+ED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAG1E;AAED,sEAAsE;AACtE,wBAAgB,OAAO,IAAI,OAAO,GAAG,IAAI,CAExC;AAED;;6BAE6B;AAC7B,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE3D"}
|
package/dist/api/backend.js
CHANGED
|
@@ -75,32 +75,56 @@ class RemoteBackend {
|
|
|
75
75
|
return this.caps.includes(capability);
|
|
76
76
|
}
|
|
77
77
|
probe() {
|
|
78
|
+
return this.probeDetail().then((r) => r.capabilities);
|
|
79
|
+
}
|
|
80
|
+
probeDetail() {
|
|
78
81
|
if (this.probed)
|
|
79
82
|
return this.probed;
|
|
83
|
+
const url = `${this.baseUrl}/meta`;
|
|
80
84
|
this.probed = (async () => {
|
|
81
85
|
try {
|
|
82
86
|
// Unauthenticated on purpose: "what are you" must be answerable before a
|
|
83
87
|
// credential is sorted out, or a signed-out machine could never discover
|
|
84
88
|
// that signing in would be worth it.
|
|
85
|
-
const res = await this.fetchImpl(
|
|
89
|
+
const res = await this.fetchImpl(url);
|
|
90
|
+
// A 404 here is the classic wrong-path failure, and an API's 404 is an
|
|
91
|
+
// HTML page -- so it is a question nobody answered, not a capability
|
|
92
|
+
// list of zero.
|
|
86
93
|
if (!res.ok)
|
|
87
|
-
return [];
|
|
88
|
-
|
|
94
|
+
return { url, answered: false, capabilities: [], reason: `HTTP ${res.status}` };
|
|
95
|
+
let body;
|
|
96
|
+
try {
|
|
97
|
+
body = await res.json();
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// 200 with an HTML page is what a proxy or a CDN returns. Reading that
|
|
101
|
+
// as "holds no sessions" is the reassuring-direction failure.
|
|
102
|
+
return { url, answered: false, capabilities: [], reason: 'the reply was not JSON' };
|
|
103
|
+
}
|
|
89
104
|
this.caps = Array.isArray(body.capabilities)
|
|
90
105
|
? body.capabilities.filter((c) => typeof c === 'string')
|
|
91
106
|
: [];
|
|
92
|
-
return this.caps;
|
|
107
|
+
return { url, answered: true, capabilities: this.caps };
|
|
93
108
|
}
|
|
94
|
-
catch {
|
|
95
|
-
// Unreachable,
|
|
96
|
-
// mean the same thing: do not use it for anything.
|
|
109
|
+
catch (err) {
|
|
110
|
+
// Unreachable, aborted, DNS, TLS. None of them is an answer.
|
|
97
111
|
this.caps = [];
|
|
98
|
-
return
|
|
112
|
+
return { url, answered: false, capabilities: [], reason: reasonOf(err) };
|
|
99
113
|
}
|
|
100
114
|
})();
|
|
101
115
|
return this.probed;
|
|
102
116
|
}
|
|
103
117
|
}
|
|
118
|
+
/** A one-line cause for a probe that never landed. Deliberately terse: it goes
|
|
119
|
+
* into a startup banner next to the URL, where the URL is the actionable half. */
|
|
120
|
+
function reasonOf(err) {
|
|
121
|
+
if (err instanceof Error) {
|
|
122
|
+
if (err.name === 'AbortError' || err.name === 'TimeoutError')
|
|
123
|
+
return 'no reply (timed out)';
|
|
124
|
+
return err.message || 'unreachable';
|
|
125
|
+
}
|
|
126
|
+
return 'unreachable';
|
|
127
|
+
}
|
|
104
128
|
let current = null;
|
|
105
129
|
/**
|
|
106
130
|
* Point at a backend, or at none.
|
package/dist/api/backend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../api/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AAE/D;;eAEe;AACf,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;AACvC,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AACjC,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../api/backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/** The findings file, beside SESSION.jsonl in the room's own directory. */
|
|
2
|
+
export declare const FINDINGS_FILE = "FINDINGS.jsonl";
|
|
3
|
+
export declare const FINDING_KIND: "finding";
|
|
4
|
+
/** Per-finding length cap, in characters. The same number as `MAX_ROOM_BRIEF`
|
|
5
|
+
* on purpose: a finding is a decision stated once, at about the length a room's
|
|
6
|
+
* whole purpose takes to state. */
|
|
7
|
+
export declare const MAX_FINDING_TEXT = 500;
|
|
8
|
+
/** How many ACTIVE findings a room may hold at once.
|
|
9
|
+
*
|
|
10
|
+
* This is a per-turn cost multiplier, not a storage limit: the document is
|
|
11
|
+
* rendered into every participant's system prompt on every turn, so its size is
|
|
12
|
+
* paid once per turn per participant for the rest of the room. 16 x 500 chars
|
|
13
|
+
* is ~8K characters, roughly 2K tokens -- the same order as the transcript
|
|
14
|
+
* overhead a room already carries, and comfortably under what would start
|
|
15
|
+
* crowding out the conversation itself. It is also about the point past which a
|
|
16
|
+
* findings list stops being a document a person reads and becomes a log they
|
|
17
|
+
* skim: a room with seventeen live decisions has not converged.
|
|
18
|
+
*
|
|
19
|
+
* At the cap, recording is REFUSED (out loud, naming the cap) rather than
|
|
20
|
+
* silently dropping the oldest: a room that quietly loses its first decision to
|
|
21
|
+
* make room for its seventeenth is worse than one told to tidy up. Revising and
|
|
22
|
+
* withdrawing still work at the cap, so the room can always make space. */
|
|
23
|
+
export declare const MAX_ROOM_FINDINGS = 16;
|
|
24
|
+
export type FindingLine = {
|
|
25
|
+
k: typeof FINDING_KIND;
|
|
26
|
+
op: 'record';
|
|
27
|
+
id: string;
|
|
28
|
+
at: number;
|
|
29
|
+
by: string;
|
|
30
|
+
text: string;
|
|
31
|
+
} | {
|
|
32
|
+
k: typeof FINDING_KIND;
|
|
33
|
+
op: 'revise';
|
|
34
|
+
id: string;
|
|
35
|
+
at: number;
|
|
36
|
+
by: string;
|
|
37
|
+
text: string;
|
|
38
|
+
} | {
|
|
39
|
+
k: typeof FINDING_KIND;
|
|
40
|
+
op: 'withdraw';
|
|
41
|
+
id: string;
|
|
42
|
+
at: number;
|
|
43
|
+
by: string;
|
|
44
|
+
reason: string;
|
|
45
|
+
};
|
|
46
|
+
export interface Finding {
|
|
47
|
+
id: string;
|
|
48
|
+
text: string;
|
|
49
|
+
/** The participant id that first recorded it. */
|
|
50
|
+
by: string;
|
|
51
|
+
at: number;
|
|
52
|
+
/** Who last revised it, and when. Null for a finding nobody has corrected. */
|
|
53
|
+
revisedBy: string | null;
|
|
54
|
+
revisedAt: number | null;
|
|
55
|
+
/** Set once the room retired this finding. Kept rather than deleted: the
|
|
56
|
+
* document should be able to say what the room stopped believing. */
|
|
57
|
+
withdrawn: {
|
|
58
|
+
by: string;
|
|
59
|
+
at: number;
|
|
60
|
+
reason: string;
|
|
61
|
+
} | null;
|
|
62
|
+
}
|
|
63
|
+
/** One edit a participant (agent or human) asks for. Deliberately id-based for
|
|
64
|
+
* `revise`/`withdraw`: a positional edit would mean something different by the
|
|
65
|
+
* time it was applied. */
|
|
66
|
+
export type FindingEdit = {
|
|
67
|
+
kind: 'record';
|
|
68
|
+
text: string;
|
|
69
|
+
} | {
|
|
70
|
+
kind: 'revise';
|
|
71
|
+
id: string;
|
|
72
|
+
text: string;
|
|
73
|
+
} | {
|
|
74
|
+
kind: 'withdraw';
|
|
75
|
+
id: string;
|
|
76
|
+
reason: string;
|
|
77
|
+
};
|
|
78
|
+
export declare function encodeFindingLine(line: FindingLine): string;
|
|
79
|
+
/** Apply one line to a folded document. Exported because the engine applies a
|
|
80
|
+
* turn's edits one at a time and must plan each against the document as the
|
|
81
|
+
* PREVIOUS edit left it -- otherwise two records in one turn mint the same id. */
|
|
82
|
+
export declare function applyFindingLine(doc: readonly Finding[], line: FindingLine): Finding[];
|
|
83
|
+
/** Fold a FINDINGS.jsonl text into the document. Degrades, never throws: one
|
|
84
|
+
* malformed line must not take the whole document with it, and a line of any
|
|
85
|
+
* other kind (a file that ever ends up sharing this one) is simply not ours. */
|
|
86
|
+
export declare function foldFindings(text: string): Finding[];
|
|
87
|
+
/** The findings that still stand. What participants are shown, and what the cap
|
|
88
|
+
* counts -- a withdrawn finding costs nothing per turn and should not keep the
|
|
89
|
+
* room from recording a new one. */
|
|
90
|
+
export declare function activeFindings(doc: readonly Finding[]): Finding[];
|
|
91
|
+
/**
|
|
92
|
+
* Turn one requested edit into the line that would record it, or say why not.
|
|
93
|
+
*
|
|
94
|
+
* The ONE place an edit is validated, so the agent's tool, the human's facade
|
|
95
|
+
* call and the engine's apply step cannot drift into three different ideas of
|
|
96
|
+
* what a legal finding is. Pure: it writes nothing and mutates nothing.
|
|
97
|
+
*/
|
|
98
|
+
export declare function planFindingEdit(doc: readonly Finding[], edit: FindingEdit, by: string, at: number): {
|
|
99
|
+
ok: true;
|
|
100
|
+
line: FindingLine;
|
|
101
|
+
} | {
|
|
102
|
+
ok: false;
|
|
103
|
+
problem: string;
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Plan a WHOLE turn's worth of edits against one document, in order.
|
|
107
|
+
*
|
|
108
|
+
* Sequential and cumulative: each edit is planned against the document as the
|
|
109
|
+
* previous one left it, which is the only way two `record` calls in one turn
|
|
110
|
+
* can mint two different ids -- and the only way an edit that depends on an
|
|
111
|
+
* earlier one in the same turn (withdraw, then record in its place) can be
|
|
112
|
+
* judged against reality. A refused edit is SKIPPED with its reason collected,
|
|
113
|
+
* never fatal: one bad edit must not throw away the good ones beside it.
|
|
114
|
+
*
|
|
115
|
+
* Used by the participant's tool (to answer "what id will this get, and would
|
|
116
|
+
* it even be allowed") and by the engine (to actually write the lines), so the
|
|
117
|
+
* two can never disagree about what a turn's edits mean.
|
|
118
|
+
*/
|
|
119
|
+
export declare function planFindingEdits(doc: readonly Finding[], edits: readonly FindingEdit[], by: string, at: number): {
|
|
120
|
+
lines: FindingLine[];
|
|
121
|
+
doc: Finding[];
|
|
122
|
+
problems: string[];
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* The findings as a participant reads them, ids included so a revision or a
|
|
126
|
+
* withdrawal can name one.
|
|
127
|
+
*
|
|
128
|
+
* Active only. A withdrawn finding is still in the file (and still on screen,
|
|
129
|
+
* marked, for the person in the room) but must never be rendered here: a
|
|
130
|
+
* participant shown a retired decision alongside the live ones has no way to
|
|
131
|
+
* tell them apart and will build on the wrong one.
|
|
132
|
+
*/
|
|
133
|
+
export declare function renderFindings(doc: readonly Finding[]): string;
|
|
134
|
+
//# sourceMappingURL=findings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../../rooms/findings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/* The room's living findings document.
|
|
2
|
+
*
|
|
3
|
+
* WHAT IT IS. A room's conclusions, recorded AS the room reaches them rather
|
|
4
|
+
* than recalled once at the end. A record written when a thing is agreed is
|
|
5
|
+
* accurate; an end-of-room synthesis is a lossy re-reading of prose, and it
|
|
6
|
+
* fails exactly when the room most needs it (a close that depends on a model
|
|
7
|
+
* call is a close that can fail).
|
|
8
|
+
*
|
|
9
|
+
* WHERE IT LIVES. Beside the transcript, at
|
|
10
|
+
* `<roomsRoot>/<roomId>/FINDINGS.jsonl` -- the same directory as SESSION.jsonl,
|
|
11
|
+
* never in the project tree. A room's conclusions belong to the room, not to
|
|
12
|
+
* whatever workspace happened to be open while it ran.
|
|
13
|
+
*
|
|
14
|
+
* WHY A LOG OF EDITS AND NOT A DOCUMENT BLOB. Two participants recording in the
|
|
15
|
+
* same room must not clobber each other. A whole-document overwrite makes that
|
|
16
|
+
* the default failure: the later writer's text replaces the earlier writer's,
|
|
17
|
+
* silently and completely. So the file is an append-only log of per-finding
|
|
18
|
+
* OPS -- `record`, `revise`, `withdraw` -- each naming ONE finding by id, and
|
|
19
|
+
* the document is the fold of them. Two participants recording concurrently
|
|
20
|
+
* append two independent `record` lines and the document holds both. The worst
|
|
21
|
+
* a genuine collision can do is two revisions of the SAME finding, where the
|
|
22
|
+
* later one wins and the earlier one is still in the log, which is the failure
|
|
23
|
+
* mode of a version history rather than of a lost write.
|
|
24
|
+
*
|
|
25
|
+
* WHY IT CAN SHRINK. A document that can only grow is a log, not a document.
|
|
26
|
+
* `revise` corrects a finding in place (the previous wording stays in the log);
|
|
27
|
+
* `withdraw` retires one with a stated reason, and a withdrawn finding is
|
|
28
|
+
* marked, never erased -- a reader of the file can still see what the room
|
|
29
|
+
* believed and when it stopped believing it. Only ACTIVE findings are rendered
|
|
30
|
+
* to participants, so a withdrawn decision is never re-read as current.
|
|
31
|
+
*
|
|
32
|
+
* WHO WRITES IT. Nothing here writes anything: this module is pure. The room
|
|
33
|
+
* engine is the single writer of a room's files, exactly as it is of
|
|
34
|
+
* SESSION.jsonl (see turn.ts) -- a participant's tool records its INTENT into
|
|
35
|
+
* `ctx.runState` and the engine applies it after the turn.
|
|
36
|
+
*/
|
|
37
|
+
/** The findings file, beside SESSION.jsonl in the room's own directory. */
|
|
38
|
+
export const FINDINGS_FILE = 'FINDINGS.jsonl';
|
|
39
|
+
export const FINDING_KIND = 'finding';
|
|
40
|
+
/** Per-finding length cap, in characters. The same number as `MAX_ROOM_BRIEF`
|
|
41
|
+
* on purpose: a finding is a decision stated once, at about the length a room's
|
|
42
|
+
* whole purpose takes to state. */
|
|
43
|
+
export const MAX_FINDING_TEXT = 500;
|
|
44
|
+
/** How many ACTIVE findings a room may hold at once.
|
|
45
|
+
*
|
|
46
|
+
* This is a per-turn cost multiplier, not a storage limit: the document is
|
|
47
|
+
* rendered into every participant's system prompt on every turn, so its size is
|
|
48
|
+
* paid once per turn per participant for the rest of the room. 16 x 500 chars
|
|
49
|
+
* is ~8K characters, roughly 2K tokens -- the same order as the transcript
|
|
50
|
+
* overhead a room already carries, and comfortably under what would start
|
|
51
|
+
* crowding out the conversation itself. It is also about the point past which a
|
|
52
|
+
* findings list stops being a document a person reads and becomes a log they
|
|
53
|
+
* skim: a room with seventeen live decisions has not converged.
|
|
54
|
+
*
|
|
55
|
+
* At the cap, recording is REFUSED (out loud, naming the cap) rather than
|
|
56
|
+
* silently dropping the oldest: a room that quietly loses its first decision to
|
|
57
|
+
* make room for its seventeenth is worse than one told to tidy up. Revising and
|
|
58
|
+
* withdrawing still work at the cap, so the room can always make space. */
|
|
59
|
+
export const MAX_ROOM_FINDINGS = 16;
|
|
60
|
+
export function encodeFindingLine(line) {
|
|
61
|
+
return JSON.stringify(line) + '\n';
|
|
62
|
+
}
|
|
63
|
+
function str(v) { return typeof v === 'string' ? v.trim() : ''; }
|
|
64
|
+
/** Apply one line to a folded document. Exported because the engine applies a
|
|
65
|
+
* turn's edits one at a time and must plan each against the document as the
|
|
66
|
+
* PREVIOUS edit left it -- otherwise two records in one turn mint the same id. */
|
|
67
|
+
export function applyFindingLine(doc, line) {
|
|
68
|
+
if (line.op === 'record') {
|
|
69
|
+
if (doc.some((f) => f.id === line.id))
|
|
70
|
+
return [...doc];
|
|
71
|
+
return [...doc, {
|
|
72
|
+
id: line.id, text: line.text, by: line.by, at: line.at,
|
|
73
|
+
revisedBy: null, revisedAt: null, withdrawn: null,
|
|
74
|
+
}];
|
|
75
|
+
}
|
|
76
|
+
// A revision or a withdrawal of an id nothing recorded describes nothing:
|
|
77
|
+
// dropped, exactly as `foldRoom` drops a line written before its open.
|
|
78
|
+
const found = doc.find((f) => f.id === line.id);
|
|
79
|
+
if (!found)
|
|
80
|
+
return [...doc];
|
|
81
|
+
return doc.map((f) => {
|
|
82
|
+
if (f.id !== line.id)
|
|
83
|
+
return f;
|
|
84
|
+
if (line.op === 'revise')
|
|
85
|
+
return { ...f, text: line.text, revisedBy: line.by, revisedAt: line.at };
|
|
86
|
+
return { ...f, withdrawn: { by: line.by, at: line.at, reason: line.reason } };
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function parseFindingLine(raw) {
|
|
90
|
+
const s = raw.trim();
|
|
91
|
+
if (!s)
|
|
92
|
+
return null;
|
|
93
|
+
let parsed;
|
|
94
|
+
try {
|
|
95
|
+
parsed = JSON.parse(s);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
if (!parsed || typeof parsed !== 'object')
|
|
101
|
+
return null;
|
|
102
|
+
const o = parsed;
|
|
103
|
+
if (o.k !== FINDING_KIND)
|
|
104
|
+
return null;
|
|
105
|
+
const id = str(o.id);
|
|
106
|
+
const by = str(o.by);
|
|
107
|
+
const at = typeof o.at === 'number' && Number.isFinite(o.at) ? o.at : null;
|
|
108
|
+
if (!id || !by || at === null)
|
|
109
|
+
return null;
|
|
110
|
+
if (o.op === 'record' || o.op === 'revise') {
|
|
111
|
+
const text = str(o.text);
|
|
112
|
+
if (!text)
|
|
113
|
+
return null;
|
|
114
|
+
return { k: FINDING_KIND, op: o.op, id, at, by, text };
|
|
115
|
+
}
|
|
116
|
+
if (o.op === 'withdraw') {
|
|
117
|
+
const reason = str(o.reason);
|
|
118
|
+
if (!reason)
|
|
119
|
+
return null;
|
|
120
|
+
return { k: FINDING_KIND, op: 'withdraw', id, at, by, reason };
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
/** Fold a FINDINGS.jsonl text into the document. Degrades, never throws: one
|
|
125
|
+
* malformed line must not take the whole document with it, and a line of any
|
|
126
|
+
* other kind (a file that ever ends up sharing this one) is simply not ours. */
|
|
127
|
+
export function foldFindings(text) {
|
|
128
|
+
let doc = [];
|
|
129
|
+
for (const raw of text.split('\n')) {
|
|
130
|
+
const line = parseFindingLine(raw);
|
|
131
|
+
if (line)
|
|
132
|
+
doc = applyFindingLine(doc, line);
|
|
133
|
+
}
|
|
134
|
+
return doc;
|
|
135
|
+
}
|
|
136
|
+
/** The findings that still stand. What participants are shown, and what the cap
|
|
137
|
+
* counts -- a withdrawn finding costs nothing per turn and should not keep the
|
|
138
|
+
* room from recording a new one. */
|
|
139
|
+
export function activeFindings(doc) {
|
|
140
|
+
return doc.filter((f) => f.withdrawn === null);
|
|
141
|
+
}
|
|
142
|
+
/** The next id, never reusing one a withdrawn finding held: an id that comes
|
|
143
|
+
* back meaning something else makes the log unreadable. */
|
|
144
|
+
function nextFindingId(doc) {
|
|
145
|
+
let max = 0;
|
|
146
|
+
for (const f of doc) {
|
|
147
|
+
const n = /^f(\d+)$/.exec(f.id);
|
|
148
|
+
if (n)
|
|
149
|
+
max = Math.max(max, Number(n[1]));
|
|
150
|
+
}
|
|
151
|
+
return `f${max + 1}`;
|
|
152
|
+
}
|
|
153
|
+
function idList(doc) {
|
|
154
|
+
const active = activeFindings(doc).map((f) => f.id);
|
|
155
|
+
return active.length ? active.join(', ') : '(none)';
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Turn one requested edit into the line that would record it, or say why not.
|
|
159
|
+
*
|
|
160
|
+
* The ONE place an edit is validated, so the agent's tool, the human's facade
|
|
161
|
+
* call and the engine's apply step cannot drift into three different ideas of
|
|
162
|
+
* what a legal finding is. Pure: it writes nothing and mutates nothing.
|
|
163
|
+
*/
|
|
164
|
+
export function planFindingEdit(doc, edit, by, at) {
|
|
165
|
+
const author = str(by);
|
|
166
|
+
if (!author)
|
|
167
|
+
return { ok: false, problem: 'A finding must record who found it.' };
|
|
168
|
+
if (edit.kind === 'record') {
|
|
169
|
+
const text = str(edit.text);
|
|
170
|
+
if (!text)
|
|
171
|
+
return { ok: false, problem: 'A finding cannot be empty -- say what the room decided.' };
|
|
172
|
+
if (text.length > MAX_FINDING_TEXT) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
problem: `That finding is ${text.length} characters; the maximum is ${MAX_FINDING_TEXT}. `
|
|
176
|
+
+ 'State the decision, not the discussion that reached it.',
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (activeFindings(doc).length >= MAX_ROOM_FINDINGS) {
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
problem: `This room already holds the maximum of ${MAX_ROOM_FINDINGS} findings. `
|
|
183
|
+
+ 'Revise one that is now wrong, or withdraw one that no longer holds, and record this in its place.',
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return { ok: true, line: { k: FINDING_KIND, op: 'record', id: nextFindingId(doc), at, by: author, text } };
|
|
187
|
+
}
|
|
188
|
+
const id = str(edit.id);
|
|
189
|
+
const found = doc.find((f) => f.id === id);
|
|
190
|
+
if (!found) {
|
|
191
|
+
return { ok: false, problem: `There is no finding "${id}" in this room. The findings are: ${idList(doc)}.` };
|
|
192
|
+
}
|
|
193
|
+
if (found.withdrawn) {
|
|
194
|
+
return {
|
|
195
|
+
ok: false,
|
|
196
|
+
problem: `Finding ${id} was withdrawn (${found.withdrawn.reason}) and cannot be changed. `
|
|
197
|
+
+ 'Record a new finding instead.',
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (edit.kind === 'revise') {
|
|
201
|
+
const text = str(edit.text);
|
|
202
|
+
if (!text)
|
|
203
|
+
return { ok: false, problem: 'A revision cannot be empty -- withdraw the finding instead.' };
|
|
204
|
+
if (text.length > MAX_FINDING_TEXT) {
|
|
205
|
+
return {
|
|
206
|
+
ok: false,
|
|
207
|
+
problem: `That revision is ${text.length} characters; the maximum is ${MAX_FINDING_TEXT}.`,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return { ok: true, line: { k: FINDING_KIND, op: 'revise', id, at, by: author, text } };
|
|
211
|
+
}
|
|
212
|
+
const reason = str(edit.reason);
|
|
213
|
+
if (!reason) {
|
|
214
|
+
return { ok: false, problem: 'Withdrawing a finding needs a reason -- a decision that vanishes without one cannot be reviewed later.' };
|
|
215
|
+
}
|
|
216
|
+
return { ok: true, line: { k: FINDING_KIND, op: 'withdraw', id, at, by: author, reason } };
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Plan a WHOLE turn's worth of edits against one document, in order.
|
|
220
|
+
*
|
|
221
|
+
* Sequential and cumulative: each edit is planned against the document as the
|
|
222
|
+
* previous one left it, which is the only way two `record` calls in one turn
|
|
223
|
+
* can mint two different ids -- and the only way an edit that depends on an
|
|
224
|
+
* earlier one in the same turn (withdraw, then record in its place) can be
|
|
225
|
+
* judged against reality. A refused edit is SKIPPED with its reason collected,
|
|
226
|
+
* never fatal: one bad edit must not throw away the good ones beside it.
|
|
227
|
+
*
|
|
228
|
+
* Used by the participant's tool (to answer "what id will this get, and would
|
|
229
|
+
* it even be allowed") and by the engine (to actually write the lines), so the
|
|
230
|
+
* two can never disagree about what a turn's edits mean.
|
|
231
|
+
*/
|
|
232
|
+
export function planFindingEdits(doc, edits, by, at) {
|
|
233
|
+
let next = [...doc];
|
|
234
|
+
const lines = [];
|
|
235
|
+
const problems = [];
|
|
236
|
+
for (const edit of edits) {
|
|
237
|
+
const planned = planFindingEdit(next, edit, by, at);
|
|
238
|
+
if (!planned.ok) {
|
|
239
|
+
problems.push(planned.problem);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
lines.push(planned.line);
|
|
243
|
+
next = applyFindingLine(next, planned.line);
|
|
244
|
+
}
|
|
245
|
+
return { lines, doc: next, problems };
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* The findings as a participant reads them, ids included so a revision or a
|
|
249
|
+
* withdrawal can name one.
|
|
250
|
+
*
|
|
251
|
+
* Active only. A withdrawn finding is still in the file (and still on screen,
|
|
252
|
+
* marked, for the person in the room) but must never be rendered here: a
|
|
253
|
+
* participant shown a retired decision alongside the live ones has no way to
|
|
254
|
+
* tell them apart and will build on the wrong one.
|
|
255
|
+
*/
|
|
256
|
+
export function renderFindings(doc) {
|
|
257
|
+
const active = activeFindings(doc);
|
|
258
|
+
if (!active.length)
|
|
259
|
+
return 'Nothing has been recorded in this room yet.';
|
|
260
|
+
return active.map((f) => `${f.id} (${f.revisedBy ?? f.by}): ${f.text}`).join('\n');
|
|
261
|
+
}
|
|
262
|
+
//# sourceMappingURL=findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findings.js","sourceRoot":"","sources":["../../rooms/findings.ts"],"names":[],"mappings":"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"}
|