@bridge4dev/runner 0.69.1 → 0.70.0
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/index.js +11 -0
- package/dist/journal.d.ts +8 -1
- package/dist/journal.js +5 -1
- package/dist/message-author.d.ts +29 -0
- package/dist/message-author.js +34 -0
- package/dist/protocol.d.ts +86 -0
- package/dist/protocol.js +38 -0
- package/dist/supervisor.js +38 -10
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -397,6 +397,17 @@ function runnerCapabilities(apiUrlOverride) {
|
|
|
397
397
|
* machine in the fleet is up to date.
|
|
398
398
|
*/
|
|
399
399
|
agentOutsideFolder: true,
|
|
400
|
+
/**
|
|
401
|
+
* «Tell the agent who is writing»: the name the API attaches to a message
|
|
402
|
+
* (`author` on `deliver_message` and `session_message`, `promptAuthor` on
|
|
403
|
+
* the descriptor) goes on top of the agent's prompt, never into the feed.
|
|
404
|
+
*
|
|
405
|
+
* Announced for the settings card only, and as a warning rather than a
|
|
406
|
+
* refusal, like `agentOutsideFolder` above it: an older runner drops the
|
|
407
|
+
* field unread and the message still arrives — just unsigned — so a
|
|
408
|
+
* manager can record the decision before the last machine is current.
|
|
409
|
+
*/
|
|
410
|
+
messageAuthors: true,
|
|
400
411
|
/**
|
|
401
412
|
* #137: this runner can read a repository that has no commits yet.
|
|
402
413
|
*
|
package/dist/journal.d.ts
CHANGED
|
@@ -30,6 +30,13 @@ export interface PendingMessage {
|
|
|
30
30
|
* those cannot be recalled, which is correct — they predate the feature.
|
|
31
31
|
*/
|
|
32
32
|
seq?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Who typed it, as DevBridge shows them — present only when the project has
|
|
35
|
+
* «Tell the agent who is writing» switched on. Held with the words so a
|
|
36
|
+
* message that waited out a restart is still signed for the agent when it
|
|
37
|
+
* finally goes (`message-author.ts`).
|
|
38
|
+
*/
|
|
39
|
+
author?: string;
|
|
33
40
|
}
|
|
34
41
|
export interface PendingAttachment {
|
|
35
42
|
id: string;
|
|
@@ -140,7 +147,7 @@ export declare class SessionJournal {
|
|
|
140
147
|
* it is queued in memory, so the ordering is "on disk, then held" — a crash
|
|
141
148
|
* between the two costs a duplicate delivery at worst, never a lost message.
|
|
142
149
|
*/
|
|
143
|
-
appendPending(text: string, attachments?: PendingAttachment[], seq?: number): PendingMessage;
|
|
150
|
+
appendPending(text: string, attachments?: PendingAttachment[], seq?: number, author?: string): PendingMessage;
|
|
144
151
|
/** The message reached an agent — stop replaying it after a restart. */
|
|
145
152
|
resolvePending(id: string): void;
|
|
146
153
|
/**
|
package/dist/journal.js
CHANGED
|
@@ -97,6 +97,7 @@ export class SessionJournal {
|
|
|
97
97
|
text: parsed.text,
|
|
98
98
|
...(parsed.attachments?.length ? { attachments: parsed.attachments } : {}),
|
|
99
99
|
...(typeof parsed.seq === 'number' ? { seq: parsed.seq } : {}),
|
|
100
|
+
...(typeof parsed.author === 'string' ? { author: parsed.author } : {}),
|
|
100
101
|
});
|
|
101
102
|
// Ids are `p<n>`; keep the counter above whatever the file holds so a
|
|
102
103
|
// restarted runner cannot mint an id that is already in flight.
|
|
@@ -157,6 +158,7 @@ export class SessionJournal {
|
|
|
157
158
|
text: record.text,
|
|
158
159
|
...(record.attachments?.length ? { attachments: record.attachments } : {}),
|
|
159
160
|
...(record.seq === undefined ? {} : { seq: record.seq }),
|
|
161
|
+
...(record.author === undefined ? {} : { author: record.author }),
|
|
160
162
|
ts: new Date().toISOString(),
|
|
161
163
|
});
|
|
162
164
|
}
|
|
@@ -294,13 +296,14 @@ export class SessionJournal {
|
|
|
294
296
|
* it is queued in memory, so the ordering is "on disk, then held" — a crash
|
|
295
297
|
* between the two costs a duplicate delivery at worst, never a lost message.
|
|
296
298
|
*/
|
|
297
|
-
appendPending(text, attachments, seq) {
|
|
299
|
+
appendPending(text, attachments, seq, author) {
|
|
298
300
|
const id = `p${this.pendingCounter++}`;
|
|
299
301
|
const record = {
|
|
300
302
|
id,
|
|
301
303
|
text,
|
|
302
304
|
...(attachments?.length ? { attachments } : {}),
|
|
303
305
|
...(seq === undefined ? {} : { seq }),
|
|
306
|
+
...(author === undefined ? {} : { author }),
|
|
304
307
|
};
|
|
305
308
|
this.write({
|
|
306
309
|
kind: 'pending',
|
|
@@ -308,6 +311,7 @@ export class SessionJournal {
|
|
|
308
311
|
text,
|
|
309
312
|
...(attachments?.length ? { attachments } : {}),
|
|
310
313
|
...(seq === undefined ? {} : { seq }),
|
|
314
|
+
...(author === undefined ? {} : { author }),
|
|
311
315
|
ts: new Date().toISOString(),
|
|
312
316
|
});
|
|
313
317
|
this.pendingById.set(id, record);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who typed this — for the agent, not for the feed.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the agent needs it
|
|
5
|
+
*
|
|
6
|
+
* Several people write into one session: the developer, a colleague forwarding
|
|
7
|
+
* a client's email, the platform owner stepping in to help. The runner echoes
|
|
8
|
+
* every message into the feed as `role: 'user'` and the API stamps the author
|
|
9
|
+
* onto that echo for people to see — but the AGENT got the bare words, and
|
|
10
|
+
* could not tell one person from another. A project prompt that says «if Andy
|
|
11
|
+
* writes, do not start development — say you are waiting for Dima» had nothing
|
|
12
|
+
* to go on.
|
|
13
|
+
*
|
|
14
|
+
* ## What it is, and what it is not
|
|
15
|
+
*
|
|
16
|
+
* A line the platform puts on top of the composed prompt, named after the
|
|
17
|
+
* person as DevBridge shows them. The feed never sees it: `acceptUserMessage`
|
|
18
|
+
* echoes the text the person typed, and this runs on the way to the agent, the
|
|
19
|
+
* same place the attachment paths are added. It is a hint to the model, not an
|
|
20
|
+
* access control — the project's real permissions are its roles, and the line
|
|
21
|
+
* carries no authority of its own. The API decides per message whether to send
|
|
22
|
+
* a name at all (the project setting «Tell the agent who is writing»); the
|
|
23
|
+
* runner adds the line whenever one arrives and never invents one.
|
|
24
|
+
*
|
|
25
|
+
* The name comes off the wire and is treated as such: folded onto one line,
|
|
26
|
+
* trimmed, and an empty one means no line at all.
|
|
27
|
+
*/
|
|
28
|
+
export declare function signMessage(text: string, author: string | undefined): string;
|
|
29
|
+
//# sourceMappingURL=message-author.d.ts.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who typed this — for the agent, not for the feed.
|
|
3
|
+
*
|
|
4
|
+
* ## Why the agent needs it
|
|
5
|
+
*
|
|
6
|
+
* Several people write into one session: the developer, a colleague forwarding
|
|
7
|
+
* a client's email, the platform owner stepping in to help. The runner echoes
|
|
8
|
+
* every message into the feed as `role: 'user'` and the API stamps the author
|
|
9
|
+
* onto that echo for people to see — but the AGENT got the bare words, and
|
|
10
|
+
* could not tell one person from another. A project prompt that says «if Andy
|
|
11
|
+
* writes, do not start development — say you are waiting for Dima» had nothing
|
|
12
|
+
* to go on.
|
|
13
|
+
*
|
|
14
|
+
* ## What it is, and what it is not
|
|
15
|
+
*
|
|
16
|
+
* A line the platform puts on top of the composed prompt, named after the
|
|
17
|
+
* person as DevBridge shows them. The feed never sees it: `acceptUserMessage`
|
|
18
|
+
* echoes the text the person typed, and this runs on the way to the agent, the
|
|
19
|
+
* same place the attachment paths are added. It is a hint to the model, not an
|
|
20
|
+
* access control — the project's real permissions are its roles, and the line
|
|
21
|
+
* carries no authority of its own. The API decides per message whether to send
|
|
22
|
+
* a name at all (the project setting «Tell the agent who is writing»); the
|
|
23
|
+
* runner adds the line whenever one arrives and never invents one.
|
|
24
|
+
*
|
|
25
|
+
* The name comes off the wire and is treated as such: folded onto one line,
|
|
26
|
+
* trimmed, and an empty one means no line at all.
|
|
27
|
+
*/
|
|
28
|
+
export function signMessage(text, author) {
|
|
29
|
+
const name = (author ?? '').replace(/\s+/g, ' ').trim();
|
|
30
|
+
if (name === '')
|
|
31
|
+
return text;
|
|
32
|
+
return `[Message from ${name}]\n\n${text}`;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=message-author.js.map
|
package/dist/protocol.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import type { HostLoadFrame } from './host-load.js';
|
|
3
3
|
import type { SessionLimitsFrame } from './session-limits.js';
|
|
4
|
+
/**
|
|
5
|
+
* The longest name the wire accepts for «who typed this». A display name from a
|
|
6
|
+
* profile, not a document — anything longer is not a name, and the field is a
|
|
7
|
+
* nicety: over the limit it is dropped and the message goes on without it.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MESSAGE_AUTHOR_MAX = 200;
|
|
4
10
|
export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
5
11
|
id: z.ZodString;
|
|
6
12
|
kind: z.ZodEnum<["TICKET", "CHAT"]>;
|
|
@@ -71,6 +77,18 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
71
77
|
* arrives as `undefined`, which is the same as «auto-update is off».
|
|
72
78
|
*/
|
|
73
79
|
agentLatestVersion: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
80
|
+
/**
|
|
81
|
+
* Who handed over the first message — the person who created the session, as
|
|
82
|
+
* DevBridge shows them. Sent only when the project has «Tell the agent who is
|
|
83
|
+
* writing» switched on and the prompt is not empty; `composeInitialPrompt`
|
|
84
|
+
* puts the name on top of the whole first message (`message-author.ts`).
|
|
85
|
+
*
|
|
86
|
+
* Optional, and absent means «no name»: an older API never sends it, and a
|
|
87
|
+
* project with the setting off gets exactly the first message it always had.
|
|
88
|
+
* `.catch(undefined)` like its neighbours — a bad value costs the signature,
|
|
89
|
+
* never the descriptor, never the `hello_ack` it rides in (QA-100 MAJOR-1).
|
|
90
|
+
*/
|
|
91
|
+
promptAuthor: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
74
92
|
workspace: z.ZodObject<{
|
|
75
93
|
id: z.ZodString;
|
|
76
94
|
path: z.ZodString;
|
|
@@ -277,6 +295,7 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
277
295
|
pausedUntil?: string | null | undefined;
|
|
278
296
|
backgroundTasks?: number | undefined;
|
|
279
297
|
agentLatestVersion?: string | undefined;
|
|
298
|
+
promptAuthor?: string | undefined;
|
|
280
299
|
skipAgentPrompt?: boolean | undefined;
|
|
281
300
|
branchHint?: string | undefined;
|
|
282
301
|
branchPlan?: {
|
|
@@ -328,6 +347,7 @@ export declare const SessionDescriptorSchema: z.ZodObject<{
|
|
|
328
347
|
pausedUntil?: unknown;
|
|
329
348
|
backgroundTasks?: unknown;
|
|
330
349
|
agentLatestVersion?: unknown;
|
|
350
|
+
promptAuthor?: unknown;
|
|
331
351
|
skipAgentPrompt?: unknown;
|
|
332
352
|
branchHint?: unknown;
|
|
333
353
|
branchPlan?: unknown;
|
|
@@ -362,6 +382,14 @@ export declare const QuestionAnswerShape: {
|
|
|
362
382
|
notes?: string | undefined;
|
|
363
383
|
}>, "many">>;
|
|
364
384
|
readonly text: z.ZodOptional<z.ZodString>;
|
|
385
|
+
/**
|
|
386
|
+
* Who typed `text` — sent only when the project has «Tell the agent who is
|
|
387
|
+
* writing» on. Signs the free text of a «discuss» reply (words a person typed
|
|
388
|
+
* into an open card are a message like any other) and the words rescued when
|
|
389
|
+
* the card turns out to be dead; a pick stays a pick. `.catch(undefined)`
|
|
390
|
+
* like the message author: a bad name costs the signature, not the answer.
|
|
391
|
+
*/
|
|
392
|
+
readonly author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
365
393
|
};
|
|
366
394
|
/** The `answer_question` command's arguments — the shape above on its own. */
|
|
367
395
|
export declare const QuestionAnswerArgsSchema: z.ZodObject<{
|
|
@@ -384,10 +412,19 @@ export declare const QuestionAnswerArgsSchema: z.ZodObject<{
|
|
|
384
412
|
notes?: string | undefined;
|
|
385
413
|
}>, "many">>;
|
|
386
414
|
readonly text: z.ZodOptional<z.ZodString>;
|
|
415
|
+
/**
|
|
416
|
+
* Who typed `text` — sent only when the project has «Tell the agent who is
|
|
417
|
+
* writing» on. Signs the free text of a «discuss» reply (words a person typed
|
|
418
|
+
* into an open card are a message like any other) and the words rescued when
|
|
419
|
+
* the card turns out to be dead; a pick stays a pick. `.catch(undefined)`
|
|
420
|
+
* like the message author: a bad name costs the signature, not the answer.
|
|
421
|
+
*/
|
|
422
|
+
readonly author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
387
423
|
}, "strip", z.ZodTypeAny, {
|
|
388
424
|
action: "answer" | "discuss";
|
|
389
425
|
askId: string;
|
|
390
426
|
text?: string | undefined;
|
|
427
|
+
author?: string | undefined;
|
|
391
428
|
answers?: {
|
|
392
429
|
values: string[];
|
|
393
430
|
questionId: string;
|
|
@@ -398,6 +435,7 @@ export declare const QuestionAnswerArgsSchema: z.ZodObject<{
|
|
|
398
435
|
action: "answer" | "discuss";
|
|
399
436
|
askId: string;
|
|
400
437
|
text?: string | undefined;
|
|
438
|
+
author?: unknown;
|
|
401
439
|
answers?: {
|
|
402
440
|
values: string[];
|
|
403
441
|
questionId: string;
|
|
@@ -432,9 +470,18 @@ export declare const DeliverMessageArgsSchema: z.ZodObject<{
|
|
|
432
470
|
mimeType: string;
|
|
433
471
|
fileSize: number;
|
|
434
472
|
}>, "many">>>;
|
|
473
|
+
/**
|
|
474
|
+
* Who typed it, as DevBridge shows them — present only when the project has
|
|
475
|
+
* «Tell the agent who is writing» switched on. Goes on top of the composed
|
|
476
|
+
* prompt (`message-author.ts`), never into the feed echo. `.catch(undefined)`
|
|
477
|
+
* for the same reason attachments have it: a malformed name must cost the
|
|
478
|
+
* signature, never the sentence the person typed.
|
|
479
|
+
*/
|
|
480
|
+
author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
435
481
|
}, "strip", z.ZodTypeAny, {
|
|
436
482
|
text: string;
|
|
437
483
|
messageId: string;
|
|
484
|
+
author?: string | undefined;
|
|
438
485
|
attachments?: {
|
|
439
486
|
id: string;
|
|
440
487
|
fileName: string;
|
|
@@ -444,6 +491,7 @@ export declare const DeliverMessageArgsSchema: z.ZodObject<{
|
|
|
444
491
|
}, {
|
|
445
492
|
text: string;
|
|
446
493
|
messageId: string;
|
|
494
|
+
author?: unknown;
|
|
447
495
|
attachments?: unknown;
|
|
448
496
|
}>;
|
|
449
497
|
export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
@@ -521,6 +569,18 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
521
569
|
* arrives as `undefined`, which is the same as «auto-update is off».
|
|
522
570
|
*/
|
|
523
571
|
agentLatestVersion: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
572
|
+
/**
|
|
573
|
+
* Who handed over the first message — the person who created the session, as
|
|
574
|
+
* DevBridge shows them. Sent only when the project has «Tell the agent who is
|
|
575
|
+
* writing» switched on and the prompt is not empty; `composeInitialPrompt`
|
|
576
|
+
* puts the name on top of the whole first message (`message-author.ts`).
|
|
577
|
+
*
|
|
578
|
+
* Optional, and absent means «no name»: an older API never sends it, and a
|
|
579
|
+
* project with the setting off gets exactly the first message it always had.
|
|
580
|
+
* `.catch(undefined)` like its neighbours — a bad value costs the signature,
|
|
581
|
+
* never the descriptor, never the `hello_ack` it rides in (QA-100 MAJOR-1).
|
|
582
|
+
*/
|
|
583
|
+
promptAuthor: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
524
584
|
workspace: z.ZodObject<{
|
|
525
585
|
id: z.ZodString;
|
|
526
586
|
path: z.ZodString;
|
|
@@ -727,6 +787,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
727
787
|
pausedUntil?: string | null | undefined;
|
|
728
788
|
backgroundTasks?: number | undefined;
|
|
729
789
|
agentLatestVersion?: string | undefined;
|
|
790
|
+
promptAuthor?: string | undefined;
|
|
730
791
|
skipAgentPrompt?: boolean | undefined;
|
|
731
792
|
branchHint?: string | undefined;
|
|
732
793
|
branchPlan?: {
|
|
@@ -778,6 +839,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
778
839
|
pausedUntil?: unknown;
|
|
779
840
|
backgroundTasks?: unknown;
|
|
780
841
|
agentLatestVersion?: unknown;
|
|
842
|
+
promptAuthor?: unknown;
|
|
781
843
|
skipAgentPrompt?: unknown;
|
|
782
844
|
branchHint?: unknown;
|
|
783
845
|
branchPlan?: unknown;
|
|
@@ -827,6 +889,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
827
889
|
pausedUntil?: string | null | undefined;
|
|
828
890
|
backgroundTasks?: number | undefined;
|
|
829
891
|
agentLatestVersion?: string | undefined;
|
|
892
|
+
promptAuthor?: string | undefined;
|
|
830
893
|
skipAgentPrompt?: boolean | undefined;
|
|
831
894
|
branchHint?: string | undefined;
|
|
832
895
|
branchPlan?: {
|
|
@@ -884,6 +947,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
884
947
|
pausedUntil?: unknown;
|
|
885
948
|
backgroundTasks?: unknown;
|
|
886
949
|
agentLatestVersion?: unknown;
|
|
950
|
+
promptAuthor?: unknown;
|
|
887
951
|
skipAgentPrompt?: unknown;
|
|
888
952
|
branchHint?: unknown;
|
|
889
953
|
branchPlan?: unknown;
|
|
@@ -990,6 +1054,18 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
990
1054
|
* arrives as `undefined`, which is the same as «auto-update is off».
|
|
991
1055
|
*/
|
|
992
1056
|
agentLatestVersion: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
1057
|
+
/**
|
|
1058
|
+
* Who handed over the first message — the person who created the session, as
|
|
1059
|
+
* DevBridge shows them. Sent only when the project has «Tell the agent who is
|
|
1060
|
+
* writing» switched on and the prompt is not empty; `composeInitialPrompt`
|
|
1061
|
+
* puts the name on top of the whole first message (`message-author.ts`).
|
|
1062
|
+
*
|
|
1063
|
+
* Optional, and absent means «no name»: an older API never sends it, and a
|
|
1064
|
+
* project with the setting off gets exactly the first message it always had.
|
|
1065
|
+
* `.catch(undefined)` like its neighbours — a bad value costs the signature,
|
|
1066
|
+
* never the descriptor, never the `hello_ack` it rides in (QA-100 MAJOR-1).
|
|
1067
|
+
*/
|
|
1068
|
+
promptAuthor: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
993
1069
|
workspace: z.ZodObject<{
|
|
994
1070
|
id: z.ZodString;
|
|
995
1071
|
path: z.ZodString;
|
|
@@ -1196,6 +1272,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1196
1272
|
pausedUntil?: string | null | undefined;
|
|
1197
1273
|
backgroundTasks?: number | undefined;
|
|
1198
1274
|
agentLatestVersion?: string | undefined;
|
|
1275
|
+
promptAuthor?: string | undefined;
|
|
1199
1276
|
skipAgentPrompt?: boolean | undefined;
|
|
1200
1277
|
branchHint?: string | undefined;
|
|
1201
1278
|
branchPlan?: {
|
|
@@ -1247,6 +1324,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1247
1324
|
pausedUntil?: unknown;
|
|
1248
1325
|
backgroundTasks?: unknown;
|
|
1249
1326
|
agentLatestVersion?: unknown;
|
|
1327
|
+
promptAuthor?: unknown;
|
|
1250
1328
|
skipAgentPrompt?: unknown;
|
|
1251
1329
|
branchHint?: unknown;
|
|
1252
1330
|
branchPlan?: unknown;
|
|
@@ -1295,6 +1373,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1295
1373
|
pausedUntil?: string | null | undefined;
|
|
1296
1374
|
backgroundTasks?: number | undefined;
|
|
1297
1375
|
agentLatestVersion?: string | undefined;
|
|
1376
|
+
promptAuthor?: string | undefined;
|
|
1298
1377
|
skipAgentPrompt?: boolean | undefined;
|
|
1299
1378
|
branchHint?: string | undefined;
|
|
1300
1379
|
branchPlan?: {
|
|
@@ -1349,6 +1428,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1349
1428
|
pausedUntil?: unknown;
|
|
1350
1429
|
backgroundTasks?: unknown;
|
|
1351
1430
|
agentLatestVersion?: unknown;
|
|
1431
|
+
promptAuthor?: unknown;
|
|
1352
1432
|
skipAgentPrompt?: unknown;
|
|
1353
1433
|
branchHint?: unknown;
|
|
1354
1434
|
branchPlan?: unknown;
|
|
@@ -1380,10 +1460,12 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1380
1460
|
mimeType: string;
|
|
1381
1461
|
fileSize: number;
|
|
1382
1462
|
}>, "many">>>;
|
|
1463
|
+
author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
1383
1464
|
}, "strip", z.ZodTypeAny, {
|
|
1384
1465
|
text: string;
|
|
1385
1466
|
sessionId: string;
|
|
1386
1467
|
type: "session_message";
|
|
1468
|
+
author?: string | undefined;
|
|
1387
1469
|
attachments?: {
|
|
1388
1470
|
id: string;
|
|
1389
1471
|
fileName: string;
|
|
@@ -1395,6 +1477,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1395
1477
|
text: string;
|
|
1396
1478
|
sessionId: string;
|
|
1397
1479
|
type: "session_message";
|
|
1480
|
+
author?: unknown;
|
|
1398
1481
|
attachments?: unknown;
|
|
1399
1482
|
messageId?: unknown;
|
|
1400
1483
|
}>, z.ZodObject<{
|
|
@@ -1435,6 +1518,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1435
1518
|
notes?: string | undefined;
|
|
1436
1519
|
}>, "many">>;
|
|
1437
1520
|
text: z.ZodOptional<z.ZodString>;
|
|
1521
|
+
author: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
1438
1522
|
type: z.ZodLiteral<"question_answer">;
|
|
1439
1523
|
sessionId: z.ZodString;
|
|
1440
1524
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -1443,6 +1527,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1443
1527
|
action: "answer" | "discuss";
|
|
1444
1528
|
askId: string;
|
|
1445
1529
|
text?: string | undefined;
|
|
1530
|
+
author?: string | undefined;
|
|
1446
1531
|
answers?: {
|
|
1447
1532
|
values: string[];
|
|
1448
1533
|
questionId: string;
|
|
@@ -1455,6 +1540,7 @@ export declare const GatewayFrameSchema: z.ZodDiscriminatedUnion<"type", [z.ZodO
|
|
|
1455
1540
|
action: "answer" | "discuss";
|
|
1456
1541
|
askId: string;
|
|
1457
1542
|
text?: string | undefined;
|
|
1543
|
+
author?: unknown;
|
|
1458
1544
|
answers?: {
|
|
1459
1545
|
values: string[];
|
|
1460
1546
|
questionId: string;
|
package/dist/protocol.js
CHANGED
|
@@ -3,6 +3,12 @@ import { AGENT_DB_VALUES, AGENT_VERSION_PATTERN } from './agent-registry.js';
|
|
|
3
3
|
// Wire protocol with the DevBridge API (mirror of
|
|
4
4
|
// packages/api/src/modules/dev-orchestration/dev-orchestration.schema.ts —
|
|
5
5
|
// the API side is the source of truth).
|
|
6
|
+
/**
|
|
7
|
+
* The longest name the wire accepts for «who typed this». A display name from a
|
|
8
|
+
* profile, not a document — anything longer is not a name, and the field is a
|
|
9
|
+
* nicety: over the limit it is dropped and the message goes on without it.
|
|
10
|
+
*/
|
|
11
|
+
export const MESSAGE_AUTHOR_MAX = 200;
|
|
6
12
|
export const SessionDescriptorSchema = z.object({
|
|
7
13
|
id: z.string().uuid(),
|
|
8
14
|
kind: z.enum(['TICKET', 'CHAT']),
|
|
@@ -102,6 +108,18 @@ export const SessionDescriptorSchema = z.object({
|
|
|
102
108
|
.regex(new RegExp(AGENT_VERSION_PATTERN))
|
|
103
109
|
.optional()
|
|
104
110
|
.catch(undefined),
|
|
111
|
+
/**
|
|
112
|
+
* Who handed over the first message — the person who created the session, as
|
|
113
|
+
* DevBridge shows them. Sent only when the project has «Tell the agent who is
|
|
114
|
+
* writing» switched on and the prompt is not empty; `composeInitialPrompt`
|
|
115
|
+
* puts the name on top of the whole first message (`message-author.ts`).
|
|
116
|
+
*
|
|
117
|
+
* Optional, and absent means «no name»: an older API never sends it, and a
|
|
118
|
+
* project with the setting off gets exactly the first message it always had.
|
|
119
|
+
* `.catch(undefined)` like its neighbours — a bad value costs the signature,
|
|
120
|
+
* never the descriptor, never the `hello_ack` it rides in (QA-100 MAJOR-1).
|
|
121
|
+
*/
|
|
122
|
+
promptAuthor: z.string().max(MESSAGE_AUTHOR_MAX).optional().catch(undefined),
|
|
105
123
|
workspace: z.object({
|
|
106
124
|
id: z.string().uuid(),
|
|
107
125
|
path: z.string(),
|
|
@@ -263,6 +281,14 @@ export const QuestionAnswerShape = {
|
|
|
263
281
|
.max(4)
|
|
264
282
|
.optional(),
|
|
265
283
|
text: z.string().max(20_000).optional(),
|
|
284
|
+
/**
|
|
285
|
+
* Who typed `text` — sent only when the project has «Tell the agent who is
|
|
286
|
+
* writing» on. Signs the free text of a «discuss» reply (words a person typed
|
|
287
|
+
* into an open card are a message like any other) and the words rescued when
|
|
288
|
+
* the card turns out to be dead; a pick stays a pick. `.catch(undefined)`
|
|
289
|
+
* like the message author: a bad name costs the signature, not the answer.
|
|
290
|
+
*/
|
|
291
|
+
author: z.string().max(MESSAGE_AUTHOR_MAX).optional().catch(undefined),
|
|
266
292
|
};
|
|
267
293
|
/** The `answer_question` command's arguments — the shape above on its own. */
|
|
268
294
|
export const QuestionAnswerArgsSchema = z.object(QuestionAnswerShape);
|
|
@@ -295,6 +321,14 @@ export const DeliverMessageArgsSchema = z.object({
|
|
|
295
321
|
messageId: z.string().min(1).max(120),
|
|
296
322
|
text: z.string(),
|
|
297
323
|
attachments: MessageAttachmentsSchema,
|
|
324
|
+
/**
|
|
325
|
+
* Who typed it, as DevBridge shows them — present only when the project has
|
|
326
|
+
* «Tell the agent who is writing» switched on. Goes on top of the composed
|
|
327
|
+
* prompt (`message-author.ts`), never into the feed echo. `.catch(undefined)`
|
|
328
|
+
* for the same reason attachments have it: a malformed name must cost the
|
|
329
|
+
* signature, never the sentence the person typed.
|
|
330
|
+
*/
|
|
331
|
+
author: z.string().max(MESSAGE_AUTHOR_MAX).optional().catch(undefined),
|
|
298
332
|
});
|
|
299
333
|
export const GatewayFrameSchema = z.discriminatedUnion('type', [
|
|
300
334
|
z.object({
|
|
@@ -334,6 +368,10 @@ export const GatewayFrameSchema = z.discriminatedUnion('type', [
|
|
|
334
368
|
// fetched with the runner's own token. `.catch` so a malformed entry costs
|
|
335
369
|
// the attachments, never the message the user typed.
|
|
336
370
|
attachments: MessageAttachmentsSchema,
|
|
371
|
+
// Who typed it — the same field `deliver_message` carries, on the legacy
|
|
372
|
+
// door too, so a project with the setting on is not silently unsigned on
|
|
373
|
+
// an API that still sends the frame.
|
|
374
|
+
author: z.string().max(MESSAGE_AUTHOR_MAX).optional().catch(undefined),
|
|
337
375
|
}),
|
|
338
376
|
z.object({
|
|
339
377
|
type: z.literal('permission_answer'),
|
package/dist/supervisor.js
CHANGED
|
@@ -35,6 +35,7 @@ import { countRunningCommands, freshStallState, pickKillCandidate, readScopeProc
|
|
|
35
35
|
import { machineReserveBytes } from './service-unit.js';
|
|
36
36
|
import { sessionLimitsChangedEnough, sessionLimitsHeartbeatDue, SESSION_LIMITS_HEARTBEAT_MS, } from './session-limits.js';
|
|
37
37
|
import { composeMessageWithAttachments, saveAttachments, } from './attachments.js';
|
|
38
|
+
import { signMessage } from './message-author.js';
|
|
38
39
|
import { applyRewind, createCheckpoint, dropCheckpoints, listCheckpoints, MAX_BUSY_SESSIONS, previewRewind, pruneCheckpoints, } from './checkpoints.js';
|
|
39
40
|
import { DeliverMessageArgsSchema, QuestionAnswerArgsSchema } from './protocol.js';
|
|
40
41
|
import { availableModes, MODE_REFUSED_TEXT } from './adapters/types.js';
|
|
@@ -1828,7 +1829,7 @@ export class Supervisor {
|
|
|
1828
1829
|
// command yet. Its outcome goes nowhere because nobody is listening —
|
|
1829
1830
|
// which is the whole defect ticket #299 is about, and why the command
|
|
1830
1831
|
// below exists.
|
|
1831
|
-
this.acceptUserMessage(frame.sessionId, frame.text, frame.attachments, frame.messageId ?? undefined);
|
|
1832
|
+
this.acceptUserMessage(frame.sessionId, frame.text, frame.attachments, frame.messageId ?? undefined, frame.author);
|
|
1832
1833
|
break;
|
|
1833
1834
|
case 'permission_answer': {
|
|
1834
1835
|
const running = this.sessions.get(frame.sessionId);
|
|
@@ -2021,7 +2022,7 @@ export class Supervisor {
|
|
|
2021
2022
|
if (orphaned) {
|
|
2022
2023
|
this.orphanMessages.delete(descriptor.id);
|
|
2023
2024
|
for (const message of orphaned) {
|
|
2024
|
-
this.acceptUserMessage(descriptor.id, message.text, message.attachments, message.messageId);
|
|
2025
|
+
this.acceptUserMessage(descriptor.id, message.text, message.attachments, message.messageId, message.author);
|
|
2025
2026
|
}
|
|
2026
2027
|
}
|
|
2027
2028
|
try {
|
|
@@ -4293,11 +4294,18 @@ export class Supervisor {
|
|
|
4293
4294
|
// own events reach the feed a microtask later, so the user's words still
|
|
4294
4295
|
// land before the agent's reaction — and on a miss we can hand the text to
|
|
4295
4296
|
// the ordinary delivery path, which does the echo itself.
|
|
4297
|
+
//
|
|
4298
|
+
// The free text of a «discuss» reply is a person's message like any other,
|
|
4299
|
+
// so it is signed for the agent the way `acceptUserMessage` signs one
|
|
4300
|
+
// (`message-author.ts`) — and only for the agent: the echo below stays the
|
|
4301
|
+
// words as typed. A pick (`answer`) is structured and gets no line.
|
|
4296
4302
|
const accepted = running.session?.answerQuestion({
|
|
4297
4303
|
askId: frame.askId,
|
|
4298
4304
|
action: frame.action,
|
|
4299
4305
|
...(frame.answers ? { answers: frame.answers } : {}),
|
|
4300
|
-
...(frame.text !== undefined
|
|
4306
|
+
...(frame.text !== undefined
|
|
4307
|
+
? { text: frame.action === 'discuss' ? signMessage(frame.text, frame.author) : frame.text }
|
|
4308
|
+
: {}),
|
|
4301
4309
|
});
|
|
4302
4310
|
if (accepted) {
|
|
4303
4311
|
running.answeredAsks.add(frame.askId);
|
|
@@ -4372,7 +4380,7 @@ export class Supervisor {
|
|
|
4372
4380
|
this.sendEvent(running, 'system_note', {
|
|
4373
4381
|
text: 'That question is no longer open — sending your reply as an ordinary message instead.',
|
|
4374
4382
|
});
|
|
4375
|
-
this.acceptUserMessage(frame.sessionId, rescued);
|
|
4383
|
+
this.acceptUserMessage(frame.sessionId, rescued, undefined, undefined, frame.author);
|
|
4376
4384
|
return 'not_open';
|
|
4377
4385
|
}
|
|
4378
4386
|
// Nothing to deliver — but the API optimistically flipped the session to
|
|
@@ -4395,7 +4403,14 @@ export class Supervisor {
|
|
|
4395
4403
|
* thrown away, because «I wrote it into a socket» was never an answer to
|
|
4396
4404
|
* «did the runner get it».
|
|
4397
4405
|
*/
|
|
4398
|
-
acceptUserMessage(sessionId, text, attachments, messageId
|
|
4406
|
+
acceptUserMessage(sessionId, text, attachments, messageId,
|
|
4407
|
+
/**
|
|
4408
|
+
* Who typed it, as DevBridge shows them — sent only when the project has
|
|
4409
|
+
* «Tell the agent who is writing» on. Goes on top of the COMPOSED prompt
|
|
4410
|
+
* (`message-author.ts`), the way attachment paths do; the feed echo below
|
|
4411
|
+
* stays the bare text, exactly as the person wrote it.
|
|
4412
|
+
*/
|
|
4413
|
+
author) {
|
|
4399
4414
|
const running = this.sessions.get(sessionId);
|
|
4400
4415
|
if (!running) {
|
|
4401
4416
|
// The API believes this session lives here but the runner lost track of
|
|
@@ -4417,6 +4432,7 @@ export class Supervisor {
|
|
|
4417
4432
|
text,
|
|
4418
4433
|
...(attachments?.length ? { attachments } : {}),
|
|
4419
4434
|
...(messageId ? { messageId } : {}),
|
|
4435
|
+
...(author ? { author } : {}),
|
|
4420
4436
|
});
|
|
4421
4437
|
this.orphanMessages.set(sessionId, queued.slice(-Supervisor.ORPHAN_MESSAGE_CAP));
|
|
4422
4438
|
this.ws.send({ type: 'session_unknown', sessionId });
|
|
@@ -4483,17 +4499,17 @@ export class Supervisor {
|
|
|
4483
4499
|
// check — the outbox flushes on reconnect, and the git service posts its
|
|
4484
4500
|
// own conflict tasks. Held here rather than delivered, so «на паузе»
|
|
4485
4501
|
// means the same thing whichever door the words came through.
|
|
4486
|
-
this.queueMessage(running, running.journal.appendPending(text, attachments, originSeq));
|
|
4502
|
+
this.queueMessage(running, running.journal.appendPending(text, attachments, originSeq, author));
|
|
4487
4503
|
return 'accepted';
|
|
4488
4504
|
}
|
|
4489
4505
|
this.enqueueDelivery(running, async () => {
|
|
4490
|
-
const composed = await this.materializeAttachments(running, text, attachments);
|
|
4506
|
+
const composed = signMessage(await this.materializeAttachments(running, text, attachments), author);
|
|
4491
4507
|
if (this.isStale(running)) {
|
|
4492
4508
|
// The session ended while the files downloaded. Park the message on
|
|
4493
4509
|
// disk rather than dropping it — «Продолжить» carries it to the agent.
|
|
4494
4510
|
// Announced like every other queueing decision: a bubble that is
|
|
4495
4511
|
// waiting must say so, whichever door it came through.
|
|
4496
|
-
const parked = running.journal.appendPending(text, attachments, originSeq);
|
|
4512
|
+
const parked = running.journal.appendPending(text, attachments, originSeq, author);
|
|
4497
4513
|
if (parked.seq !== undefined) {
|
|
4498
4514
|
this.sendEvent(running, 'message_queued', { targetSeq: parked.seq });
|
|
4499
4515
|
}
|
|
@@ -5077,7 +5093,10 @@ export class Supervisor {
|
|
|
5077
5093
|
const parts = [];
|
|
5078
5094
|
try {
|
|
5079
5095
|
for (const record of pending) {
|
|
5080
|
-
|
|
5096
|
+
// Each part under its own name: two people who wrote while the
|
|
5097
|
+
// session was held go to the agent together, and the agent must
|
|
5098
|
+
// still be able to tell which words are whose.
|
|
5099
|
+
parts.push(signMessage(await this.materializeAttachments(running, record.text, record.attachments), record.author));
|
|
5081
5100
|
}
|
|
5082
5101
|
}
|
|
5083
5102
|
catch (error) {
|
|
@@ -6507,7 +6526,7 @@ export class Supervisor {
|
|
|
6507
6526
|
error: parsed.error.issues[0]?.message ?? 'malformed message',
|
|
6508
6527
|
});
|
|
6509
6528
|
}
|
|
6510
|
-
const outcome = this.acceptUserMessage(sessionId, parsed.data.text, parsed.data.attachments, parsed.data.messageId);
|
|
6529
|
+
const outcome = this.acceptUserMessage(sessionId, parsed.data.text, parsed.data.attachments, parsed.data.messageId, parsed.data.author);
|
|
6511
6530
|
// `ok` is about the RELAY, like the answer above: `unknown_session` is
|
|
6512
6531
|
// the one case the API can fix by asking again after it has re-sent
|
|
6513
6532
|
// the descriptor, so it is the one case reported as a failure.
|
|
@@ -8219,6 +8238,15 @@ export function carryOnMessage(refusedWhole) {
|
|
|
8219
8238
|
* prompt beside `CLAUDE.md` — which is read last and therefore overrides ours.
|
|
8220
8239
|
*/
|
|
8221
8240
|
export function composeInitialPrompt(descriptor) {
|
|
8241
|
+
const body = composeInitialBody(descriptor);
|
|
8242
|
+
// Signed like every later message (`message-author.ts`): the API names the
|
|
8243
|
+
// creator only when the project has «Tell the agent who is writing» on. The
|
|
8244
|
+
// name goes above the assignment too — handing a ticket over is that
|
|
8245
|
+
// person's act. An empty first message stays empty: there is nothing to sign
|
|
8246
|
+
// and the agent is meant to boot and wait.
|
|
8247
|
+
return body === '' ? body : signMessage(body, descriptor.promptAuthor);
|
|
8248
|
+
}
|
|
8249
|
+
function composeInitialBody(descriptor) {
|
|
8222
8250
|
// A free chat may carry tickets as CONTEXT. Assigning them would put an agent
|
|
8223
8251
|
// nobody asked onto somebody else's ticket (session 13).
|
|
8224
8252
|
if (descriptor.kind === 'CHAT' || descriptor.tickets.length === 0)
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const RUNNER_VERSION = "0.
|
|
1
|
+
export declare const RUNNER_VERSION = "0.70.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
package/package.json
CHANGED