pi-roundtable-coding 0.9.3 → 0.9.5
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/CHANGELOG.md +18 -0
- package/README.md +7 -1
- package/package.json +2 -2
- package/src/coding-desk.ts +38 -0
- package/src/coding-plugin.ts +16 -0
- package/src/index.ts +1 -0
- package/src/pi-coding-worker.ts +40 -1
- package/src/worker-entry.ts +28 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.5] - 2026-10-10
|
|
6
|
+
|
|
7
|
+
0.9.4 was tagged but never published (its release checks failed on the recorded prompt texts); everything listed under it is released in 0.9.5.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- A coding worker posts its progress into its thread as it works, as the host's turns do: longer or structured text as ordinary messages, and short narration with the tools it called in one small-text progress message edited in place. Its approval cards come after the text written before them, the report is posted once at the end, and a failed post or edit is logged without failing the job. `interimText: "off"` (on `coding` and `CodingDeskOptions`) keeps today's thread of task, cards and report; `interimPrimaryChars` sets the length of primary text (default 400). It needs pi-roundtable 0.9.5's `DispatchThread.interim`.
|
|
12
|
+
- `CodingWorker.run` takes an optional fourth argument, `CodingProgress` (`messageEnd(message)`, `toolStart(name)`), which `PiCodingWorker` feeds from the worker's session over its IPC channel (message text and tool names only, never thinking).
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
|
|
16
|
+
- A worker's approval card no longer expires after 30 minutes: the worker waits for the answer, with no countdown on the card, until it is stopped; the waiting does not count against `timeoutMs`.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- A worker's shell gets the host's scratch dir (`env.scratchDir`): TMPDIR points to it, and writes, redirects and removals inside it run without the owner's approval, as in the agents' shell. Before, every scratch-dir command a worker ran asked the owner.
|
|
21
|
+
- A worker whose host has a scratch dir is told it in its system prompt, after the host's own prompt or the default, so a task need not say where temporary files and test homes go.
|
|
22
|
+
|
|
5
23
|
## [0.9.3] - 2026-10-10
|
|
6
24
|
|
|
7
25
|
- Release in lockstep with pi-roundtable 0.9.3; no package-specific behavior changes.
|
package/README.md
CHANGED
|
@@ -128,9 +128,13 @@ The parent consults `shellHoldRule`, additional `holds`, and the host's linked h
|
|
|
128
128
|
When `threads` is configured, progress and cards stay in a thread opened under the resolved run's `origin`; if no thread can open, calls remain held rather than falling back to another channel's approval cards.
|
|
129
129
|
Without `threads`, the resolved report channel's prompts are used.
|
|
130
130
|
`threadText` controls the initial post, held-action post, approval title and final report; the thread is archived before `onResult` is called, and a failed thread post/close does not discard result delivery.
|
|
131
|
+
While it works, the worker posts its progress into its thread, as the host's own turns do: text of `interimPrimaryChars` (400) characters or more, or written with a Markdown heading, list, table or code fence, as ordinary messages, and short narration with the tools it called in one small-text progress message edited in place.
|
|
132
|
+
The thread's cards come after the text written before them, the final report is posted once, and a failed progress post or edit is logged and never fails the job.
|
|
133
|
+
`interimText: "off"` posts only the task, the held-action notices, the cards and the report; a thread whose host cannot edit its posts gets no progress either.
|
|
131
134
|
`promptSlot` tracks these cards and `workTimeout` excludes their waiting time from the worker's budget (one hour by default).
|
|
132
135
|
`timeoutMs` must be positive and finite, and at most 2,147,483,647 ms to fit the host timer.
|
|
133
|
-
|
|
136
|
+
A worker's card has no grace period and no deadline: the worker waits for the answer until it is stopped, and the waiting does not count against its time.
|
|
137
|
+
An approved call runs; a declined, missing or failed card blocks it and instructs the worker not to retry or work around the refusal.
|
|
134
138
|
Unapproved actions appear in the report rather than running later automatically.
|
|
135
139
|
By default worker answers are capped at 20,000 characters and the Held list keeps ten entries of at most 1,000 characters each, with explicit truncation and omission notices; `limits` changes each bound.
|
|
136
140
|
A worker failure carries its exit category and numeric code; git and gh stderr and the worker's own error text reach the report only after `scrubDiagnostic` masks credentials, and are cut at `diagnosticChars`.
|
|
@@ -181,6 +185,8 @@ The `CODING` service exposes `shelf: RepoShelf` and `desk: CodingDesk` for trust
|
|
|
181
185
|
| `toolText` | package wording | Trusted description and argument descriptions for each repository tool, as `{ repo_task: { description, parameters: { task: "…" } } }`; it never changes a tool's arguments or approval rules. |
|
|
182
186
|
| `threads` | none | Public `DispatchThreads`-compatible progress and approval thread port. |
|
|
183
187
|
| `threadText` | English package text | Thread introduction, held-action notice, approval title and final report. |
|
|
188
|
+
| `interimText` | `"on"` | `"off"` keeps the worker's progress out of its thread; pass the host config's `interimText` to follow it. |
|
|
189
|
+
| `interimPrimaryChars` | `400` | Length from which a worker's intermediate text is posted as its own message. |
|
|
184
190
|
| `workerWorkspace` | individual clone | Trusted shell-policy write boundary; not an OS sandbox. |
|
|
185
191
|
| `workerPrompt` | generic worker instructions | Trusted standing prompt replacement; it cannot bypass approval or cleanup. |
|
|
186
192
|
| `workerBlockText` | "The owner declined / has not approved this call. Do not retry it or work around it; list it under Held in your report." | Trusted wording of what the worker reads when a call is declined or held, from `(answer, action)`; it never changes who is held, and the desk lists only unanswered calls as held. |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-roundtable-coding",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"description": "Repository shelves and owner-approved Pi coding workers for pi-roundtable",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@earendil-works/pi-ai": ">=1.0.0 <2",
|
|
45
45
|
"@biomejs/biome": "2.5.15",
|
|
46
46
|
"@types/bun": "1.4.2",
|
|
47
|
-
"pi-roundtable": "0.9.
|
|
47
|
+
"pi-roundtable": "0.9.5",
|
|
48
48
|
"typescript": "7.0.2"
|
|
49
49
|
}
|
|
50
50
|
}
|
package/src/coding-desk.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ChannelKey,
|
|
3
3
|
HeldCall,
|
|
4
|
+
InterimTextMode,
|
|
4
5
|
Logger,
|
|
5
6
|
OwnerPrompts,
|
|
6
7
|
ThinkingLevel,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
approvalCard,
|
|
11
12
|
type DispatchThread,
|
|
12
13
|
type DispatchThreads,
|
|
14
|
+
InterimPoster,
|
|
13
15
|
promptSlot,
|
|
14
16
|
workTimeout,
|
|
15
17
|
} from "pi-roundtable/kit";
|
|
@@ -34,11 +36,24 @@ export interface CodingJob {
|
|
|
34
36
|
startedAt: Date;
|
|
35
37
|
startHead: string;
|
|
36
38
|
}
|
|
39
|
+
/** What the worker writes and runs as it goes, for its thread's progress posts. */
|
|
40
|
+
export interface CodingProgress {
|
|
41
|
+
/** A finished message of the worker's session: its role, stop reason, and text. */
|
|
42
|
+
messageEnd(message: {
|
|
43
|
+
role: string;
|
|
44
|
+
content?: unknown;
|
|
45
|
+
stopReason?: string;
|
|
46
|
+
}): void;
|
|
47
|
+
/** A tool the worker started. */
|
|
48
|
+
toolStart(name: string): void;
|
|
49
|
+
}
|
|
37
50
|
export interface CodingWorker {
|
|
51
|
+
/** `progress`, when given, hears the session's messages and tools as the worker goes. */
|
|
38
52
|
run(
|
|
39
53
|
job: CodingJob & { dir: string },
|
|
40
54
|
signal: AbortSignal,
|
|
41
55
|
review: (call: HeldCall) => Promise<HeldCallAnswer>,
|
|
56
|
+
progress?: CodingProgress,
|
|
42
57
|
): Promise<string>;
|
|
43
58
|
}
|
|
44
59
|
export interface CodingResult {
|
|
@@ -65,6 +80,13 @@ export interface CodingDeskOptions {
|
|
|
65
80
|
logger: Logger;
|
|
66
81
|
timeoutMs?: number;
|
|
67
82
|
limits?: CodingLimits;
|
|
83
|
+
/**
|
|
84
|
+
* Whether the worker posts the text it writes before its report into its thread as it goes,
|
|
85
|
+
* as the host's turns do; "on" by default. A thread whose host cannot edit its posts gets none.
|
|
86
|
+
*/
|
|
87
|
+
interimText?: InterimTextMode;
|
|
88
|
+
/** Length from which an intermediate text is posted as its own message; default 400. */
|
|
89
|
+
interimPrimaryChars?: number;
|
|
68
90
|
}
|
|
69
91
|
/** What a coding report keeps of a long run; each is a count of characters or entries, or `Infinity` for no bound. */
|
|
70
92
|
export interface CodingLimits {
|
|
@@ -212,6 +234,7 @@ export class CodingDesk {
|
|
|
212
234
|
this.#options.limits?.heldEntries ?? MAX_HELD_ENTRIES;
|
|
213
235
|
const maxHeldChars = this.#options.limits?.heldChars ?? MAX_HELD_CHARS;
|
|
214
236
|
let cancel = () => {};
|
|
237
|
+
let interim: InterimPoster | undefined;
|
|
215
238
|
let timedOut = false;
|
|
216
239
|
let outcome: CodingResult["outcome"];
|
|
217
240
|
try {
|
|
@@ -235,11 +258,22 @@ export class CodingDesk {
|
|
|
235
258
|
}
|
|
236
259
|
if (controller.signal.aborted)
|
|
237
260
|
throw new AgentError("the worker was stopped");
|
|
261
|
+
// The worker's progress goes to its thread as it works, under the report's name.
|
|
262
|
+
if (job.thread?.interim && this.#options.interimText !== "off")
|
|
263
|
+
interim = new InterimPoster(job.thread.interim, {
|
|
264
|
+
logger: this.#options.logger,
|
|
265
|
+
channel: job.thread.channel,
|
|
266
|
+
...(this.#options.interimPrimaryChars
|
|
267
|
+
? { primaryChars: this.#options.interimPrimaryChars }
|
|
268
|
+
: {}),
|
|
269
|
+
});
|
|
270
|
+
const poster = interim;
|
|
238
271
|
slot.bind(
|
|
239
272
|
threads
|
|
240
273
|
? job.thread && prompts?.(job.thread.channel)
|
|
241
274
|
: prompts?.(job.channel),
|
|
242
275
|
`Coding worker #${job.id}`,
|
|
276
|
+
poster ? () => poster.flush() : undefined,
|
|
243
277
|
);
|
|
244
278
|
cancel = workTimeout(timeoutMs, slot, () => {
|
|
245
279
|
timedOut = true;
|
|
@@ -268,6 +302,7 @@ export class CodingDesk {
|
|
|
268
302
|
);
|
|
269
303
|
held.push(entry);
|
|
270
304
|
try {
|
|
305
|
+
await interim?.flush();
|
|
271
306
|
await job.thread?.post(
|
|
272
307
|
threadText?.held?.(entry, job) ?? `Held: ${entry}`,
|
|
273
308
|
);
|
|
@@ -282,6 +317,7 @@ export class CodingDesk {
|
|
|
282
317
|
{ ...job, dir },
|
|
283
318
|
controller.signal,
|
|
284
319
|
review,
|
|
320
|
+
interim,
|
|
285
321
|
);
|
|
286
322
|
if (controller.signal.aborted)
|
|
287
323
|
throw new AgentError("the worker was stopped");
|
|
@@ -304,6 +340,8 @@ export class CodingDesk {
|
|
|
304
340
|
} finally {
|
|
305
341
|
cancel();
|
|
306
342
|
slot.unbind();
|
|
343
|
+
// What the worker wrote lands before its report.
|
|
344
|
+
await interim?.flush();
|
|
307
345
|
}
|
|
308
346
|
let state: RepoState | undefined;
|
|
309
347
|
let commits: string[] = [];
|
package/src/coding-plugin.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
defineTool,
|
|
5
5
|
type HoldCheck,
|
|
6
6
|
IDENTITY,
|
|
7
|
+
type InterimTextMode,
|
|
7
8
|
PluginError,
|
|
8
9
|
SKILLS,
|
|
9
10
|
SYSTEM_PRINCIPAL,
|
|
@@ -99,6 +100,14 @@ export interface CodingOptions {
|
|
|
99
100
|
toolText?: Partial<Record<RepoToolName, CodingToolText>>;
|
|
100
101
|
threads?: Pick<DispatchThreads, "open">;
|
|
101
102
|
threadText?: CodingThreadText;
|
|
103
|
+
/**
|
|
104
|
+
* Whether a worker posts its progress into its thread as it goes: longer text as messages, short
|
|
105
|
+
* narration and its tools in one edited small-text message. Default "on"; "off" posts only the
|
|
106
|
+
* task and the report. Pass the host config's `interimText` to follow it.
|
|
107
|
+
*/
|
|
108
|
+
interimText?: InterimTextMode;
|
|
109
|
+
/** Length from which a worker's intermediate text is its own message; default 400. */
|
|
110
|
+
interimPrimaryChars?: number;
|
|
102
111
|
workerWorkspace?: string;
|
|
103
112
|
workerPrompt?: (dir: string) => string;
|
|
104
113
|
/** How much of a long run a report keeps; see `CodingLimits`. */
|
|
@@ -168,6 +177,9 @@ export function coding(options: CodingOptions) {
|
|
|
168
177
|
packages: options.workerPackages,
|
|
169
178
|
agentDir: options.agentDir,
|
|
170
179
|
workspace: options.workerWorkspace,
|
|
180
|
+
...(context.env.scratchDir
|
|
181
|
+
? { scratchDir: context.env.scratchDir }
|
|
182
|
+
: {}),
|
|
171
183
|
prompt: options.workerPrompt,
|
|
172
184
|
blockText: options.workerBlockText,
|
|
173
185
|
diagnosticChars: options.diagnosticChars,
|
|
@@ -183,6 +195,10 @@ export function coding(options: CodingOptions) {
|
|
|
183
195
|
logger: context.logger,
|
|
184
196
|
threads: options.threads,
|
|
185
197
|
threadText: options.threadText,
|
|
198
|
+
...(options.interimText ? { interimText: options.interimText } : {}),
|
|
199
|
+
...(options.interimPrimaryChars
|
|
200
|
+
? { interimPrimaryChars: options.interimPrimaryChars }
|
|
201
|
+
: {}),
|
|
186
202
|
prompts: (channel) => context.surfaces.prompts(channel),
|
|
187
203
|
deliver:
|
|
188
204
|
options.onResult ??
|
package/src/index.ts
CHANGED
package/src/pi-coding-worker.ts
CHANGED
|
@@ -2,7 +2,12 @@ import { fileURLToPath } from "node:url";
|
|
|
2
2
|
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
import type { HeldCall, HoldCheck } from "pi-roundtable";
|
|
4
4
|
import { AgentError, canonicalJson, shellHoldRule } from "pi-roundtable/kit";
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
CodingJob,
|
|
7
|
+
CodingProgress,
|
|
8
|
+
CodingWorker,
|
|
9
|
+
HeldCallAnswer,
|
|
10
|
+
} from "./coding-desk.ts";
|
|
6
11
|
import { CodingWorkerFailure } from "./worker-failure.ts";
|
|
7
12
|
|
|
8
13
|
export interface PiCodingWorkerOptions {
|
|
@@ -14,6 +19,11 @@ export interface PiCodingWorkerOptions {
|
|
|
14
19
|
holds?: HoldCheck;
|
|
15
20
|
/** Trusted host policy boundary for writes; defaults to the individual clone. */
|
|
16
21
|
workspace?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The host's scratch dir: the worker's shell runs with TMPDIR pointing to it, and writes and
|
|
24
|
+
* removals inside it run without a hold, as in the agents' shell.
|
|
25
|
+
*/
|
|
26
|
+
scratchDir?: string;
|
|
17
27
|
/** Trusted host standing prompt, replacing the generic worker instructions. */
|
|
18
28
|
prompt?: (dir: string) => string;
|
|
19
29
|
/**
|
|
@@ -31,6 +41,10 @@ interface WorkerMessage {
|
|
|
31
41
|
input?: Record<string, unknown>;
|
|
32
42
|
report?: string;
|
|
33
43
|
message?: string;
|
|
44
|
+
role?: string;
|
|
45
|
+
stopReason?: string;
|
|
46
|
+
text?: string;
|
|
47
|
+
name?: string;
|
|
34
48
|
}
|
|
35
49
|
function isMessage(value: unknown): value is WorkerMessage {
|
|
36
50
|
return (
|
|
@@ -51,6 +65,7 @@ export class PiCodingWorker implements CodingWorker {
|
|
|
51
65
|
job: CodingJob & { dir: string },
|
|
52
66
|
signal: AbortSignal,
|
|
53
67
|
review: (call: HeldCall) => Promise<HeldCallAnswer>,
|
|
68
|
+
progress?: CodingProgress,
|
|
54
69
|
): Promise<string> {
|
|
55
70
|
if (process.platform === "win32")
|
|
56
71
|
throw new AgentError("Coding workers require a POSIX host.");
|
|
@@ -65,6 +80,9 @@ export class PiCodingWorker implements CodingWorker {
|
|
|
65
80
|
],
|
|
66
81
|
{
|
|
67
82
|
cwd: job.dir,
|
|
83
|
+
...(this.#options.scratchDir
|
|
84
|
+
? { env: { ...process.env, TMPDIR: this.#options.scratchDir } }
|
|
85
|
+
: {}),
|
|
68
86
|
stdin: "ignore",
|
|
69
87
|
stdout: "ignore",
|
|
70
88
|
stderr: "ignore",
|
|
@@ -79,12 +97,30 @@ export class PiCodingWorker implements CodingWorker {
|
|
|
79
97
|
packages: this.#options.packages ?? [],
|
|
80
98
|
agentDir: this.#options.agentDir ?? getAgentDir(),
|
|
81
99
|
prompt,
|
|
100
|
+
progress: progress !== undefined,
|
|
101
|
+
...(this.#options.scratchDir
|
|
102
|
+
? { scratchDir: this.#options.scratchDir }
|
|
103
|
+
: {}),
|
|
82
104
|
});
|
|
83
105
|
} else if (
|
|
84
106
|
value.type === "report" &&
|
|
85
107
|
typeof value.report === "string"
|
|
86
108
|
) {
|
|
87
109
|
report = value.report;
|
|
110
|
+
} else if (
|
|
111
|
+
value.type === "message" &&
|
|
112
|
+
typeof value.role === "string" &&
|
|
113
|
+
typeof value.text === "string"
|
|
114
|
+
) {
|
|
115
|
+
progress?.messageEnd({
|
|
116
|
+
role: value.role,
|
|
117
|
+
content: value.text,
|
|
118
|
+
...(typeof value.stopReason === "string"
|
|
119
|
+
? { stopReason: value.stopReason }
|
|
120
|
+
: {}),
|
|
121
|
+
});
|
|
122
|
+
} else if (value.type === "tool" && typeof value.name === "string") {
|
|
123
|
+
progress?.toolStart(value.name);
|
|
88
124
|
} else if (
|
|
89
125
|
value.type === "failure" &&
|
|
90
126
|
typeof value.message === "string"
|
|
@@ -109,6 +145,9 @@ export class PiCodingWorker implements CodingWorker {
|
|
|
109
145
|
try {
|
|
110
146
|
const context = {
|
|
111
147
|
workspace: this.#options.workspace ?? job.dir,
|
|
148
|
+
...(this.#options.scratchDir
|
|
149
|
+
? { scratchDir: this.#options.scratchDir }
|
|
150
|
+
: {}),
|
|
112
151
|
};
|
|
113
152
|
const action =
|
|
114
153
|
shellHoldRule.describe(tool, input, context) ??
|
package/src/worker-entry.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
activeToolsExtension,
|
|
12
12
|
runWorkerTask,
|
|
13
13
|
SHELL_TOOLS,
|
|
14
|
+
textOf,
|
|
14
15
|
} from "pi-roundtable/kit";
|
|
15
16
|
import type { CodingJob, HeldCallAnswer } from "./coding-desk.ts";
|
|
16
17
|
|
|
@@ -20,6 +21,14 @@ interface StartMessage {
|
|
|
20
21
|
packages: string[];
|
|
21
22
|
agentDir: string;
|
|
22
23
|
prompt?: string;
|
|
24
|
+
/** The host posts the worker's progress, so the session's messages and tools go to it. */
|
|
25
|
+
progress?: boolean;
|
|
26
|
+
/** The host's scratch dir, the worker's TMPDIR, where writes and removals need no approval. */
|
|
27
|
+
scratchDir?: string;
|
|
28
|
+
}
|
|
29
|
+
/** Said to every worker whose host has a scratch dir, after the host's own prompt or the default. */
|
|
30
|
+
export function scratchDirPrompt(scratchDir: string): string {
|
|
31
|
+
return `Temporary files, test homes and throwaway clones go under the scratch dir ${scratchDir} ($TMPDIR): writes and removals there, and inside the repository, run without approval; elsewhere they wait for the owner.`;
|
|
23
32
|
}
|
|
24
33
|
export function codingWorkerPrompt(dir: string): string {
|
|
25
34
|
return [
|
|
@@ -42,6 +51,8 @@ async function run({
|
|
|
42
51
|
agentDir,
|
|
43
52
|
packages,
|
|
44
53
|
prompt,
|
|
54
|
+
progress,
|
|
55
|
+
scratchDir,
|
|
45
56
|
}: StartMessage): Promise<string> {
|
|
46
57
|
const modelRuntime = await ModelRuntime.create({
|
|
47
58
|
authPath: join(agentDir, "auth.json"),
|
|
@@ -103,7 +114,10 @@ async function run({
|
|
|
103
114
|
},
|
|
104
115
|
},
|
|
105
116
|
],
|
|
106
|
-
appendSystemPrompt: [
|
|
117
|
+
appendSystemPrompt: [
|
|
118
|
+
prompt ?? codingWorkerPrompt(job.dir),
|
|
119
|
+
...(scratchDir ? [scratchDirPrompt(scratchDir)] : []),
|
|
120
|
+
],
|
|
107
121
|
});
|
|
108
122
|
await loader.reload();
|
|
109
123
|
const { session } = await createAgentSession({
|
|
@@ -115,6 +129,19 @@ async function run({
|
|
|
115
129
|
sessionManager: SessionManager.inMemory(job.dir),
|
|
116
130
|
settingsManager: SettingsManager.inMemory({}),
|
|
117
131
|
});
|
|
132
|
+
// Only what the host's progress posts read crosses: a message's text, never its thinking.
|
|
133
|
+
if (progress)
|
|
134
|
+
session.subscribe((event) => {
|
|
135
|
+
if (event.type === "tool_execution_start")
|
|
136
|
+
process.send?.({ type: "tool", name: event.toolName });
|
|
137
|
+
if (event.type === "message_end" && event.message.role === "assistant")
|
|
138
|
+
process.send?.({
|
|
139
|
+
type: "message",
|
|
140
|
+
role: event.message.role,
|
|
141
|
+
stopReason: event.message.stopReason,
|
|
142
|
+
text: textOf(event.message.content),
|
|
143
|
+
});
|
|
144
|
+
});
|
|
118
145
|
return runWorkerTask(session, {
|
|
119
146
|
modelRuntime,
|
|
120
147
|
model: job.model,
|