@llm4ts/runner 2.21.1 → 2.22.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/AgentTree.d.ts +32 -0
- package/dist/AgentTree.d.ts.map +1 -1
- package/dist/AgentTree.js +94 -10
- package/dist/AgentTree.js.map +1 -1
- package/dist/AgentTreeSurface.d.ts +1 -1
- package/dist/AgentTreeSurface.d.ts.map +1 -1
- package/dist/AgentTreeSurface.js +5 -2
- package/dist/AgentTreeSurface.js.map +1 -1
- package/dist/FlowRunner.d.ts.map +1 -1
- package/dist/FlowRunner.js +10 -7
- package/dist/FlowRunner.js.map +1 -1
- package/dist/Profile.d.ts +166 -0
- package/dist/Profile.d.ts.map +1 -0
- package/dist/Profile.js +497 -0
- package/dist/Profile.js.map +1 -0
- package/dist/Terminal.d.ts.map +1 -1
- package/dist/Terminal.js +2 -0
- package/dist/Terminal.js.map +1 -1
- package/dist/Watch.d.ts +15 -0
- package/dist/Watch.d.ts.map +1 -1
- package/dist/Watch.js +19 -6
- package/dist/Watch.js.map +1 -1
- package/package.json +4 -3
- package/src/AgentTree.ts +136 -10
- package/src/AgentTreeSurface.ts +6 -2
- package/src/FlowRunner.ts +19 -11
- package/src/Profile.ts +645 -0
- package/src/Terminal.ts +2 -0
- package/src/Watch.ts +36 -10
package/src/Watch.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readdirSync, existsSync, statSync } from "node:fs"
|
|
2
2
|
import { join } from "node:path"
|
|
3
|
+
import * as Clock from "effect/Clock"
|
|
3
4
|
import * as Duration from "effect/Duration"
|
|
4
5
|
import * as Effect from "effect/Effect"
|
|
5
6
|
import * as Queue from "effect/Queue"
|
|
@@ -42,6 +43,8 @@ export interface WatchOptions {
|
|
|
42
43
|
readonly replay?: boolean
|
|
43
44
|
/** Replay speed-up (default 10). */
|
|
44
45
|
readonly speed?: number
|
|
46
|
+
/** A live lane with no event for this long is marked idle (`LLM4TS_IDLE_AFTER`). */
|
|
47
|
+
readonly idleAfterMs?: number
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
export interface WatchOutput {
|
|
@@ -68,7 +71,13 @@ export class WatchTargetMissing extends Schema.TaggedError<WatchTargetMissing>()
|
|
|
68
71
|
{ message: Schema.String }
|
|
69
72
|
) {}
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
/** Where a run's trace and its epic are read from. */
|
|
75
|
+
export type TraceSources = Pick<WatchDependencies, "files" | "listTraces" | "listEpics">
|
|
76
|
+
|
|
77
|
+
/** A trace to read: given, an epic's latest run, or the newest in the repository. */
|
|
78
|
+
export type TraceChoice = Pick<WatchOptions, "repo" | "trace" | "epic">
|
|
79
|
+
|
|
80
|
+
export interface WatchTarget {
|
|
72
81
|
readonly tracePath: string
|
|
73
82
|
readonly epicDir: string | undefined
|
|
74
83
|
readonly run: EpicRun | undefined
|
|
@@ -80,7 +89,7 @@ const epicsDirOf = (repo: string): string => join(repo, TraceDirectoryName, "epi
|
|
|
80
89
|
const epicOfTrace = (
|
|
81
90
|
tracePath: string,
|
|
82
91
|
repo: string,
|
|
83
|
-
dependencies:
|
|
92
|
+
dependencies: TraceSources
|
|
84
93
|
): Effect.Effect<{ readonly dir: string; readonly run: EpicRun } | undefined, FlowError> =>
|
|
85
94
|
Effect.gen(function* () {
|
|
86
95
|
const epicsDir = epicsDirOf(repo)
|
|
@@ -96,9 +105,9 @@ const epicOfTrace = (
|
|
|
96
105
|
return undefined
|
|
97
106
|
})
|
|
98
107
|
|
|
99
|
-
const
|
|
100
|
-
options:
|
|
101
|
-
dependencies:
|
|
108
|
+
export const resolveTraceTarget = (
|
|
109
|
+
options: TraceChoice,
|
|
110
|
+
dependencies: TraceSources
|
|
102
111
|
): Effect.Effect<WatchTarget, FlowError | WatchTargetMissing> =>
|
|
103
112
|
Effect.gen(function* () {
|
|
104
113
|
if (options.epic !== undefined) {
|
|
@@ -143,12 +152,14 @@ const actionWords = (run: EpicRun | undefined): string | undefined => {
|
|
|
143
152
|
/** The tree before any event: the epic's board, when the trace belongs to one. */
|
|
144
153
|
const startingTree = (
|
|
145
154
|
target: WatchTarget,
|
|
146
|
-
files: PlainFileStoreShape
|
|
155
|
+
files: PlainFileStoreShape,
|
|
156
|
+
idleAfterMs: number | undefined
|
|
147
157
|
): Effect.Effect<TreeState, FlowError> =>
|
|
148
158
|
Effect.gen(function* () {
|
|
149
159
|
const action = actionWords(target.run)
|
|
160
|
+
const idle = idleAfterMs === undefined ? {} : { idleAfterMs }
|
|
150
161
|
if (target.epicDir === undefined) {
|
|
151
|
-
return emptyTree(action === undefined ? {} : { action })
|
|
162
|
+
return emptyTree({ ...idle, ...(action === undefined ? {} : { action }) })
|
|
152
163
|
}
|
|
153
164
|
const boardDir =
|
|
154
165
|
target.run?.round === undefined
|
|
@@ -159,6 +170,7 @@ const startingTree = (
|
|
|
159
170
|
return emptyTree({
|
|
160
171
|
title: board === undefined ? `epic ${epicId}` : board.title.replace(/^Epic:\s*/u, "epic "),
|
|
161
172
|
stories: (board?.items ?? []).map((item) => ({ id: item.id, status: item.status })),
|
|
173
|
+
...idle,
|
|
162
174
|
...(action === undefined ? {} : { action })
|
|
163
175
|
})
|
|
164
176
|
})
|
|
@@ -191,10 +203,12 @@ export const makeWatchProgram = Effect.fn("@llm4ts/runner/Watch.make")(function*
|
|
|
191
203
|
options: WatchOptions,
|
|
192
204
|
dependencies: WatchDependencies
|
|
193
205
|
): Effect.fn.Return<void, FlowError | WatchTargetMissing> {
|
|
194
|
-
const target = yield*
|
|
206
|
+
const target = yield* resolveTraceTarget(options, dependencies)
|
|
195
207
|
const { files, output } = dependencies
|
|
196
208
|
const fold = (inputs: ReadonlyArray<TreeInput>): Effect.Effect<TreeState, FlowError> =>
|
|
197
|
-
Effect.map(startingTree(target, files), (start) =>
|
|
209
|
+
Effect.map(startingTree(target, files, options.idleAfterMs), (start) =>
|
|
210
|
+
inputs.reduce(reduceTree, start)
|
|
211
|
+
)
|
|
198
212
|
|
|
199
213
|
if (!output.interactive) {
|
|
200
214
|
const state = yield* Effect.flatMap(readInputs(target, files), fold)
|
|
@@ -242,7 +256,13 @@ export const makeWatchProgram = Effect.fn("@llm4ts/runner/Watch.make")(function*
|
|
|
242
256
|
while (true) {
|
|
243
257
|
const current = yield* Ref.get(inputs)
|
|
244
258
|
const count = yield* Ref.get(shown)
|
|
245
|
-
const
|
|
259
|
+
const folded = yield* fold(current.slice(0, count))
|
|
260
|
+
// Following a live run, the clock moves between events; a replay
|
|
261
|
+
// and a finished run keep the trace's own time.
|
|
262
|
+
const state =
|
|
263
|
+
options.replay !== true && folded.ended === undefined
|
|
264
|
+
? reduceTree(folded, { _tag: "Tick", at: yield* Clock.currentTimeMillis })
|
|
265
|
+
: folded
|
|
246
266
|
const text = yield* painter.paint(
|
|
247
267
|
screenLines(state, yield* Ref.get(view), output),
|
|
248
268
|
`${output.columns()}x${output.rows()}`
|
|
@@ -278,6 +298,12 @@ const nodeListEpics = (directory: string): ReadonlyArray<string> =>
|
|
|
278
298
|
? readdirSync(directory).filter((name) => statSync(join(directory, name)).isDirectory())
|
|
279
299
|
: []
|
|
280
300
|
|
|
301
|
+
export const nodeTraceSources: TraceSources = {
|
|
302
|
+
files: nodePlainFileStore,
|
|
303
|
+
listTraces: nodeListTraces,
|
|
304
|
+
listEpics: nodeListEpics
|
|
305
|
+
}
|
|
306
|
+
|
|
281
307
|
export const nodeWatchDependencies = (
|
|
282
308
|
environment: Readonly<Record<string, string | undefined>> = process.env
|
|
283
309
|
): WatchDependencies => {
|