@owlmeans/agent-common 0.1.18-rc.47 → 0.1.18-rc.49
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/README.md +174 -13
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/agent-common/SKILL.md +1 -1
- package/build/consts.d.ts +20 -0
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +103 -0
- package/build/consts.js.map +1 -1
- package/build/errors.d.ts +1 -1
- package/build/errors.js +1 -1
- package/build/helpers/conversation.d.ts +0 -9
- package/build/helpers/conversation.d.ts.map +1 -1
- package/build/helpers/conversation.js +0 -28
- package/build/helpers/conversation.js.map +1 -1
- package/build/helpers/truncate.d.ts +10 -0
- package/build/helpers/truncate.d.ts.map +1 -0
- package/build/helpers/truncate.js +29 -0
- package/build/helpers/truncate.js.map +1 -0
- package/build/index.d.ts +4 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -1
- package/build/index.js.map +1 -1
- package/build/models/pipeline-spec/types.d.ts +57 -0
- package/build/models/pipeline-spec/types.d.ts.map +1 -0
- package/build/models/pipeline-spec/types.js +2 -0
- package/build/models/pipeline-spec/types.js.map +1 -0
- package/build/models/pipeline-spec.d.ts +4 -0
- package/build/models/pipeline-spec.d.ts.map +1 -0
- package/build/models/pipeline-spec.js +171 -0
- package/build/models/pipeline-spec.js.map +1 -0
- package/build/pipeline.d.ts +4 -43
- package/build/pipeline.d.ts.map +1 -1
- package/build/pipeline.js +9 -205
- package/build/pipeline.js.map +1 -1
- package/build/results/types.d.ts +211 -0
- package/build/results/types.d.ts.map +1 -0
- package/build/results/types.js +2 -0
- package/build/results/types.js.map +1 -0
- package/build/results.d.ts +3 -55
- package/build/results.d.ts.map +1 -1
- package/build/results.js +202 -250
- package/build/results.js.map +1 -1
- package/build/types.d.ts +1 -137
- package/build/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/consts.ts +113 -0
- package/src/errors.ts +1 -1
- package/src/helpers/conversation.ts +0 -32
- package/src/helpers/truncate.ts +31 -0
- package/src/index.ts +4 -1
- package/src/models/pipeline-spec/types.ts +58 -0
- package/src/models/pipeline-spec.ts +202 -0
- package/src/pipeline.ts +10 -231
- package/src/results/types.ts +221 -0
- package/src/results.ts +229 -274
- package/src/types.ts +2 -147
- package/tests/pipeline.spec.ts +26 -29
- package/tests/results.spec.ts +24 -26
- package/build/flows.d.ts +0 -21
- package/build/flows.d.ts.map +0 -1
- package/build/flows.js +0 -105
- package/build/flows.js.map +0 -1
- package/src/flows.ts +0 -113
package/src/types.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ResourceRecord } from '@owlmeans/resource'
|
|
2
|
-
import { type AgentRunStatus,
|
|
2
|
+
import { type AgentRunStatus, PipelineRunStatus } from './consts.js'
|
|
3
3
|
import type { Inquiry } from '@owlmeans/llm-common'
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -98,6 +98,7 @@ export interface AgentRunMessage {
|
|
|
98
98
|
* the state is serialized into the run row at every step boundary, and a state that carries a
|
|
99
99
|
* document is a row that carries it too, once per step.
|
|
100
100
|
*/
|
|
101
|
+
// Kept as a type: every state shape must satisfy it without declaring an index signature.
|
|
101
102
|
export type PipelineState = Record<string, unknown>
|
|
102
103
|
|
|
103
104
|
export interface PipelineStepSpec {
|
|
@@ -229,149 +230,3 @@ export interface PipelineProgress {
|
|
|
229
230
|
skipped?: boolean
|
|
230
231
|
note?: string
|
|
231
232
|
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* ONE authoritative fact about what a step produced, small enough to be one line of a prompt.
|
|
235
|
-
*
|
|
236
|
-
* Every field is optional past `kind` and `name`, because facts differ in what matters about them:
|
|
237
|
-
* a type has a shape and an import specifier, an endpoint an alias, a method, a path and a guard, a
|
|
238
|
-
* resource a table and an accessor, a file only its path. Put scalars that have no field of their
|
|
239
|
-
* own into `attrs`.
|
|
240
|
-
*/
|
|
241
|
-
export interface CumulativeResultFact {
|
|
242
|
-
/** What the fact is about — see {@link CumulativeFactKind}. */
|
|
243
|
-
kind: string
|
|
244
|
-
/** The name to use VERBATIM. */
|
|
245
|
-
name: string
|
|
246
|
-
/** The file it lives in, relative to the project root. */
|
|
247
|
-
path?: string
|
|
248
|
-
/** The module specifier it is imported from. */
|
|
249
|
-
specifier?: string
|
|
250
|
-
/** Its shape or signature, on one line. */
|
|
251
|
-
signature?: string
|
|
252
|
-
/** Fields, parameters or columns, when there is no signature to say it. */
|
|
253
|
-
members?: string[]
|
|
254
|
-
/** Another fact's name this one points at — a returned type, a mapped table. */
|
|
255
|
-
ref?: string
|
|
256
|
-
/** Scalars without a field of their own — `method`, `path`, `guard`, `table`. */
|
|
257
|
-
attrs?: Record<string, string>
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* One step's contribution to a ledger.
|
|
262
|
-
*
|
|
263
|
-
* Keyed by `(ledger, runId, step)`. `order` places it in the ledger: the topological index of the
|
|
264
|
-
* step in its own pipeline, preceded by the index path of every step it was composed under, so a
|
|
265
|
-
* run composed as a step of another sorts inside that step, ahead of the composing step's own
|
|
266
|
-
* entry. A single number cannot say that: two pipelines' indexes are not comparable.
|
|
267
|
-
*
|
|
268
|
-
* `full` and `compact` are rendered once, when the entry is written, and never contain a timestamp,
|
|
269
|
-
* a run id or anything else a model would copy without meaning to.
|
|
270
|
-
*/
|
|
271
|
-
export interface CumulativeResultEntry extends ResourceRecord {
|
|
272
|
-
/** What entries can see each other — by default the root run of the composition. */
|
|
273
|
-
ledger: string
|
|
274
|
-
pipeline: string
|
|
275
|
-
runId: string
|
|
276
|
-
step: string
|
|
277
|
-
/** How the entry is headed in a prompt: the step, behind the path of the steps it runs under. */
|
|
278
|
-
label: string
|
|
279
|
-
order: number[]
|
|
280
|
-
/** Bumped every time the entry is re-extracted after a later step rewrote one of its files. */
|
|
281
|
-
revision: number
|
|
282
|
-
source: CumulativeResultSource
|
|
283
|
-
/** An `optional` step that failed: whatever it left behind, and a heading that says so. */
|
|
284
|
-
partial?: boolean
|
|
285
|
-
facts: CumulativeResultFact[]
|
|
286
|
-
/** The files the facts were read from — what a later rewrite is matched against. */
|
|
287
|
-
files: string[]
|
|
288
|
-
/** A model's summary, rendered and capped. NOT verified, and always labelled so. */
|
|
289
|
-
summary?: string
|
|
290
|
-
full: string
|
|
291
|
-
compact: string
|
|
292
|
-
/** Consumers that always get the full entry, by step name, or every later step. */
|
|
293
|
-
fullFor?: string[] | typeof RESULTS_EVERY_STEP
|
|
294
|
-
/** Consumers that never see the entry in their prompt. */
|
|
295
|
-
omitFor?: string[]
|
|
296
|
-
/** How many edges back the entry is still rendered in full by default. */
|
|
297
|
-
window?: number
|
|
298
|
-
updatedAt: string
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* The optional model-written summary of a step. OFF unless a step declares one.
|
|
303
|
-
*
|
|
304
|
-
* Facts are the product; a summary is for what code cannot extract — an intent, a decision taken.
|
|
305
|
-
* It is bounded by `maxChars` in code after the model answers, rendered deterministically from the
|
|
306
|
-
* schema-shaped answer, and always labelled as unverified wherever it is shown.
|
|
307
|
-
*/
|
|
308
|
-
export interface ResultSummarySpec {
|
|
309
|
-
/** Which model — interpreted by the caller's summarize callback (a model role, typically). */
|
|
310
|
-
role?: string
|
|
311
|
-
instructions: string
|
|
312
|
-
/** JSON schema of the answer. Absent means `{ summary: string }`. */
|
|
313
|
-
schema?: Record<string, unknown>
|
|
314
|
-
/** Defaults to `DEFAULT_RESULT_SUMMARY_CHARS`. */
|
|
315
|
-
maxChars?: number
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* What one step contributes, and to whom. JSON-safe, so a declaration can live in data.
|
|
320
|
-
*
|
|
321
|
-
* Extractors are named, never inlined: a declaration names what runs, and the runtime holds the
|
|
322
|
-
* code. A consumer not named in `full` or `omit` gets the full entry within `window` edges and the
|
|
323
|
-
* names only beyond it.
|
|
324
|
-
*/
|
|
325
|
-
export interface StepResultsSpec {
|
|
326
|
-
/** Named deterministic extractors, run in this order. */
|
|
327
|
-
extractors?: string[]
|
|
328
|
-
/** Later steps that get the FULL entry wherever they sit, or `'*'` for all of them. */
|
|
329
|
-
full?: string[] | typeof RESULTS_EVERY_STEP
|
|
330
|
-
/** Later steps that are never shown the entry. */
|
|
331
|
-
omit?: string[]
|
|
332
|
-
/** Overrides {@link CumulativeResultsSpec.window} for this entry. */
|
|
333
|
-
window?: number
|
|
334
|
-
/** Cap on the full rendering; facts are dropped whole, never cut. */
|
|
335
|
-
maxChars?: number
|
|
336
|
-
/** Cap on the names-only rendering. */
|
|
337
|
-
maxCompactChars?: number
|
|
338
|
-
/** Re-extract this entry when a later step rewrites one of its files. Defaults to the spec's. */
|
|
339
|
-
refresh?: boolean
|
|
340
|
-
summary?: ResultSummarySpec
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/** The pipeline-level declaration — merged from a pipeline's own and any overlay with {@link mergeResultsSpecs}. */
|
|
344
|
-
export interface CumulativeResultsSpec {
|
|
345
|
-
/** Per step, by step name. A step with no entry contributes only what it records itself. */
|
|
346
|
-
steps?: Record<string, StepResultsSpec>
|
|
347
|
-
/** Default {@link DEFAULT_RESULTS_WINDOW}. */
|
|
348
|
-
window?: number
|
|
349
|
-
/** Total characters of one view. Default `DEFAULT_RESULTS_MAX_CHARS`. */
|
|
350
|
-
maxChars?: number
|
|
351
|
-
/** Default cap of one full entry. Default {@link DEFAULT_RESULT_ENTRY_CHARS}. */
|
|
352
|
-
maxEntryChars?: number
|
|
353
|
-
/** Default cap of one names-only entry. Default {@link DEFAULT_RESULT_COMPACT_CHARS}. */
|
|
354
|
-
maxCompactChars?: number
|
|
355
|
-
/** Default for {@link StepResultsSpec.refresh}. Defaults to `true`. */
|
|
356
|
-
refresh?: boolean
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/** What a facts query may narrow by. Every field is an exact match. */
|
|
360
|
-
export interface ResultFactQuery {
|
|
361
|
-
kind?: string
|
|
362
|
-
name?: string
|
|
363
|
-
/** A producing step, by its name or by its label. */
|
|
364
|
-
step?: string
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/** What {@link renderResultEntry} needs of an entry. */
|
|
368
|
-
export type RenderableResultEntry = Pick<
|
|
369
|
-
CumulativeResultEntry, 'label' | 'source' | 'partial' | 'facts' | 'summary'
|
|
370
|
-
>
|
|
371
|
-
|
|
372
|
-
export interface ResultRenderCaps {
|
|
373
|
-
/** Cap on the full rendering. Default {@link DEFAULT_RESULT_ENTRY_CHARS}. */
|
|
374
|
-
maxChars?: number
|
|
375
|
-
/** Cap on the names-only rendering. Default {@link DEFAULT_RESULT_COMPACT_CHARS}. */
|
|
376
|
-
maxCompactChars?: number
|
|
377
|
-
}
|
package/tests/pipeline.spec.ts
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import { InquiryKind } from '@owlmeans/llm-common'
|
|
3
|
-
import {
|
|
4
|
-
INQUIRY_ANSWERS_KEY, PipelineRunStatus,
|
|
5
|
-
orderPipelineSteps, pipelineDescendants, pipelineStep, validatePipelineSpec,
|
|
6
|
-
} from '../src/index.js'
|
|
3
|
+
import { INQUIRY_ANSWERS_KEY, PipelineRunStatus, makePipelineSpecModel } from '../src/index.js'
|
|
7
4
|
import type { PipelineRun, PipelineSpec } from '../src/index.js'
|
|
8
5
|
|
|
9
6
|
/**
|
|
@@ -18,25 +15,25 @@ const spec = (steps: PipelineSpec['steps'], version = 1): PipelineSpec =>
|
|
|
18
15
|
|
|
19
16
|
describe('agent-common — pipeline spec validation', () => {
|
|
20
17
|
test('accepts a linear spec', () => {
|
|
21
|
-
expect(() =>
|
|
18
|
+
expect(() => makePipelineSpecModel(spec([
|
|
22
19
|
{ step: 'a' }, { step: 'b', after: ['a'] }, { step: 'c', after: ['b'] },
|
|
23
|
-
]))).not.toThrow()
|
|
20
|
+
])).validate()).not.toThrow()
|
|
24
21
|
})
|
|
25
22
|
|
|
26
23
|
test('refuses an empty step list, an empty alias and a bad version at once', () => {
|
|
27
|
-
expect(() =>
|
|
24
|
+
expect(() => makePipelineSpecModel({ alias: '', version: 0, steps: [] }).validate())
|
|
28
25
|
.toThrow(/alias is empty.*version.*no steps/s)
|
|
29
26
|
})
|
|
30
27
|
|
|
31
28
|
test('names EVERY fault in one message rather than the first', () => {
|
|
32
29
|
let message = ''
|
|
33
30
|
try {
|
|
34
|
-
|
|
31
|
+
makePipelineSpecModel(spec([
|
|
35
32
|
{ step: 'a' },
|
|
36
33
|
{ step: 'a' },
|
|
37
34
|
{ step: 'b', after: ['nope'] },
|
|
38
35
|
{ step: 'c', nonIdempotent: true, attempts: 3 },
|
|
39
|
-
]))
|
|
36
|
+
])).validate()
|
|
40
37
|
} catch (e) {
|
|
41
38
|
message = (e as Error).message
|
|
42
39
|
}
|
|
@@ -46,41 +43,41 @@ describe('agent-common — pipeline spec validation', () => {
|
|
|
46
43
|
})
|
|
47
44
|
|
|
48
45
|
test('refuses a step that waits on itself', () => {
|
|
49
|
-
expect(() =>
|
|
46
|
+
expect(() => makePipelineSpecModel(spec([{ step: 'a', after: ['a'] }])).validate())
|
|
50
47
|
.toThrow(/declares itself/)
|
|
51
48
|
})
|
|
52
49
|
|
|
53
50
|
test('refuses a cycle', () => {
|
|
54
|
-
expect(() =>
|
|
51
|
+
expect(() => makePipelineSpecModel(spec([
|
|
55
52
|
{ step: 'a', after: ['c'] }, { step: 'b', after: ['a'] }, { step: 'c', after: ['b'] },
|
|
56
|
-
]))).toThrow(/cycle/)
|
|
53
|
+
])).validate()).toThrow(/cycle/)
|
|
57
54
|
})
|
|
58
55
|
|
|
59
56
|
test('refuses attempts below one and a non-positive timeout', () => {
|
|
60
|
-
expect(() =>
|
|
61
|
-
expect(() =>
|
|
57
|
+
expect(() => makePipelineSpecModel(spec([{ step: 'a', attempts: 0 }])).validate()).toThrow(/attempts/)
|
|
58
|
+
expect(() => makePipelineSpecModel(spec([{ step: 'a', timeout: 0 }])).validate()).toThrow(/timeout/)
|
|
62
59
|
})
|
|
63
60
|
|
|
64
61
|
test('allows attempts above one on an idempotent step', () => {
|
|
65
|
-
expect(() =>
|
|
62
|
+
expect(() => makePipelineSpecModel(spec([{ step: 'a', attempts: 3 }])).validate()).not.toThrow()
|
|
66
63
|
})
|
|
67
64
|
})
|
|
68
65
|
|
|
69
66
|
describe('agent-common — pipeline ordering', () => {
|
|
70
67
|
test('respects `after` and keeps declaration order as the tie-break', () => {
|
|
71
68
|
// `c` and `b` are both ready after `a`; declaration order decides, not a set's iteration.
|
|
72
|
-
expect(
|
|
69
|
+
expect(makePipelineSpecModel(spec([
|
|
73
70
|
{ step: 'a' }, { step: 'c', after: ['a'] }, { step: 'b', after: ['a'] },
|
|
74
|
-
]))).toEqual(['a', 'c', 'b'])
|
|
71
|
+
])).orderSteps()).toEqual(['a', 'c', 'b'])
|
|
75
72
|
})
|
|
76
73
|
|
|
77
74
|
test('orders a fan-out/join graph so the join comes last', () => {
|
|
78
|
-
const order =
|
|
75
|
+
const order = makePipelineSpecModel(spec([
|
|
79
76
|
{ step: 'left' },
|
|
80
77
|
{ step: 'right' },
|
|
81
78
|
{ step: 'deeper', after: ['right'] },
|
|
82
79
|
{ step: 'join', after: ['left', 'deeper'] },
|
|
83
|
-
]))
|
|
80
|
+
])).orderSteps()
|
|
84
81
|
expect(order.indexOf('join')).toBe(3)
|
|
85
82
|
expect(order.indexOf('deeper')).toBeGreaterThan(order.indexOf('right'))
|
|
86
83
|
})
|
|
@@ -89,14 +86,14 @@ describe('agent-common — pipeline ordering', () => {
|
|
|
89
86
|
const declared = spec([
|
|
90
87
|
{ step: 'a' }, { step: 'b' }, { step: 'c', after: ['a', 'b'] }, { step: 'd', after: ['a'] },
|
|
91
88
|
])
|
|
92
|
-
expect(
|
|
89
|
+
expect(makePipelineSpecModel(declared).orderSteps()).toEqual(makePipelineSpecModel(declared).orderSteps())
|
|
93
90
|
})
|
|
94
91
|
|
|
95
92
|
test('throws on an unknown `after` and on a cycle', () => {
|
|
96
|
-
expect(() =>
|
|
97
|
-
expect(() =>
|
|
93
|
+
expect(() => makePipelineSpecModel(spec([{ step: 'a', after: ['ghost'] }])).orderSteps()).toThrow(/unknown step/)
|
|
94
|
+
expect(() => makePipelineSpecModel(spec([
|
|
98
95
|
{ step: 'a', after: ['b'] }, { step: 'b', after: ['a'] },
|
|
99
|
-
]))).toThrow(/cycle/)
|
|
96
|
+
])).orderSteps()).toThrow(/cycle/)
|
|
100
97
|
})
|
|
101
98
|
})
|
|
102
99
|
|
|
@@ -110,21 +107,21 @@ describe('agent-common — descendants', () => {
|
|
|
110
107
|
])
|
|
111
108
|
|
|
112
109
|
test('a step and everything that transitively waits on it, in order', () => {
|
|
113
|
-
expect(
|
|
114
|
-
expect(
|
|
110
|
+
expect(makePipelineSpecModel(graph).descendants('b')).toEqual(['b', 'd'])
|
|
111
|
+
expect(makePipelineSpecModel(graph).descendants('a')).toEqual(['a', 'b', 'c', 'd'])
|
|
115
112
|
})
|
|
116
113
|
|
|
117
114
|
test('leaves an unrelated branch alone', () => {
|
|
118
|
-
expect(
|
|
115
|
+
expect(makePipelineSpecModel(graph).descendants('b')).not.toContain('aside')
|
|
119
116
|
})
|
|
120
117
|
|
|
121
118
|
test('refuses a step the spec does not declare', () => {
|
|
122
|
-
expect(() =>
|
|
119
|
+
expect(() => makePipelineSpecModel(graph).descendants('ghost')).toThrow(/pipeline-step/)
|
|
123
120
|
})
|
|
124
121
|
|
|
125
122
|
test('pipelineStep answers null rather than throwing', () => {
|
|
126
|
-
expect(
|
|
127
|
-
expect(
|
|
123
|
+
expect(makePipelineSpecModel(graph).stepOf('ghost')).toBeNull()
|
|
124
|
+
expect(makePipelineSpecModel(graph).stepOf('a')?.step).toBe('a')
|
|
128
125
|
})
|
|
129
126
|
})
|
|
130
127
|
|
package/tests/results.spec.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import {
|
|
3
|
-
CumulativeFactKind, CumulativeResultSource, RESULTS_EVERY_STEP,
|
|
4
|
-
compareResultOrder, factKey, mergeResultsSpecs, pipelineAncestors, pipelineAncestry,
|
|
5
|
-
pipelineDescendants, renderResultEntry, renderResultSummary, resultLabel,
|
|
3
|
+
CumulativeFactKind, CumulativeResultSource, RESULTS_EVERY_STEP, cumulativeResultsHelper, makePipelineSpecModel,
|
|
6
4
|
} from '../src/index.js'
|
|
7
5
|
import type { CumulativeResultFact, PipelineSpec, RenderableResultEntry } from '../src/index.js'
|
|
8
6
|
|
|
@@ -41,14 +39,14 @@ const entry = (patch: Partial<RenderableResultEntry> = {}): RenderableResultEntr
|
|
|
41
39
|
|
|
42
40
|
describe('agent-common — pipeline ancestry', () => {
|
|
43
41
|
test('names every transitive predecessor in topological order, never the step itself', () => {
|
|
44
|
-
expect(
|
|
45
|
-
expect(
|
|
42
|
+
expect(makePipelineSpecModel(diamond).ancestors('join')).toEqual(['root', 'left', 'right', 'deeper'])
|
|
43
|
+
expect(makePipelineSpecModel(diamond).ancestors('root')).toEqual([])
|
|
46
44
|
// The mirror includes the named step; ancestry deliberately does not.
|
|
47
|
-
expect(
|
|
45
|
+
expect(makePipelineSpecModel(diamond).descendants('root')).toContain('root')
|
|
48
46
|
})
|
|
49
47
|
|
|
50
48
|
test('carries the SHORTEST distance, so a direct predecessor is depth 1', () => {
|
|
51
|
-
expect(
|
|
49
|
+
expect(makePipelineSpecModel(diamond).ancestry('join')).toEqual([
|
|
52
50
|
{ step: 'root', depth: 2 },
|
|
53
51
|
{ step: 'left', depth: 1 },
|
|
54
52
|
{ step: 'right', depth: 2 },
|
|
@@ -57,14 +55,14 @@ describe('agent-common — pipeline ancestry', () => {
|
|
|
57
55
|
})
|
|
58
56
|
|
|
59
57
|
test('refuses a step the spec does not declare', () => {
|
|
60
|
-
expect(() =>
|
|
58
|
+
expect(() => makePipelineSpecModel(diamond).ancestors('ghost')).toThrow(/pipeline-step/)
|
|
61
59
|
})
|
|
62
60
|
})
|
|
63
61
|
|
|
64
62
|
describe('agent-common — rendering an entry', () => {
|
|
65
63
|
test('the same facts render the same bytes in whatever order they arrive', () => {
|
|
66
|
-
const one = renderResultEntry(entry())
|
|
67
|
-
const two = renderResultEntry(entry({ facts: [file, create, user] }))
|
|
64
|
+
const one = cumulativeResultsHelper.renderResultEntry(entry())
|
|
65
|
+
const two = cumulativeResultsHelper.renderResultEntry(entry({ facts: [file, create, user] }))
|
|
68
66
|
|
|
69
67
|
expect(two).toEqual(one)
|
|
70
68
|
expect(one.full).toBe([
|
|
@@ -76,7 +74,7 @@ describe('agent-common — rendering an entry', () => {
|
|
|
76
74
|
})
|
|
77
75
|
|
|
78
76
|
test('the names-only form lists names by kind and says it is names only', () => {
|
|
79
|
-
expect(renderResultEntry(entry()).compact).toBe([
|
|
77
|
+
expect(cumulativeResultsHelper.renderResultEntry(entry()).compact).toBe([
|
|
80
78
|
'### types (names only)',
|
|
81
79
|
'- endpoint: `user.create`',
|
|
82
80
|
'- type: `User`',
|
|
@@ -85,7 +83,7 @@ describe('agent-common — rendering an entry', () => {
|
|
|
85
83
|
})
|
|
86
84
|
|
|
87
85
|
test('over its cap it drops whole facts, never part of one, and says how many', () => {
|
|
88
|
-
const { full } = renderResultEntry(entry(), { maxChars: 200 })
|
|
86
|
+
const { full } = cumulativeResultsHelper.renderResultEntry(entry(), { maxChars: 200 })
|
|
89
87
|
|
|
90
88
|
expect(full.length).toBeLessThanOrEqual(200)
|
|
91
89
|
expect(full).toContain('- endpoint `user.create`')
|
|
@@ -94,8 +92,8 @@ describe('agent-common — rendering an entry', () => {
|
|
|
94
92
|
})
|
|
95
93
|
|
|
96
94
|
test('a summary is always labelled unverified, and a summary alone heads the entry so', () => {
|
|
97
|
-
const withFacts = renderResultEntry(entry({ summary: 'Chose soft deletes.' })).full
|
|
98
|
-
const alone = renderResultEntry(entry({
|
|
95
|
+
const withFacts = cumulativeResultsHelper.renderResultEntry(entry({ summary: 'Chose soft deletes.' })).full
|
|
96
|
+
const alone = cumulativeResultsHelper.renderResultEntry(entry({
|
|
99
97
|
facts: [], summary: 'Chose soft deletes.', source: CumulativeResultSource.Summarized,
|
|
100
98
|
})).full
|
|
101
99
|
|
|
@@ -104,37 +102,37 @@ describe('agent-common — rendering an entry', () => {
|
|
|
104
102
|
})
|
|
105
103
|
|
|
106
104
|
test('a partial entry says the step failed, and an empty ordinary entry renders nothing', () => {
|
|
107
|
-
expect(renderResultEntry(entry({ partial: true })).full.split('\n')[0])
|
|
105
|
+
expect(cumulativeResultsHelper.renderResultEntry(entry({ partial: true })).full.split('\n')[0])
|
|
108
106
|
.toBe('### types (partial: the step failed part-way; only what it left in the files is listed)')
|
|
109
|
-
expect(renderResultEntry(entry({ facts: [] }))).toEqual({ full: '', compact: '' })
|
|
107
|
+
expect(cumulativeResultsHelper.renderResultEntry(entry({ facts: [] }))).toEqual({ full: '', compact: '' })
|
|
110
108
|
})
|
|
111
109
|
})
|
|
112
110
|
|
|
113
111
|
describe('agent-common — ledger helpers', () => {
|
|
114
112
|
test('a composed run sorts inside its composing step, ahead of that step\'s own entry', () => {
|
|
115
113
|
const keys = [[3], [1], [3, 2], [3, 1], [0], [4]]
|
|
116
|
-
expect([...keys].sort(compareResultOrder)).toEqual([[0], [1], [3, 1], [3, 2], [3], [4]])
|
|
114
|
+
expect([...keys].sort(cumulativeResultsHelper.compareResultOrder)).toEqual([[0], [1], [3, 1], [3, 2], [3], [4]])
|
|
117
115
|
})
|
|
118
116
|
|
|
119
117
|
test('labels a composed run\'s step by its path under the root run', () => {
|
|
120
|
-
expect(resultLabel('r', 'r', 'types')).toBe('types')
|
|
121
|
-
expect(resultLabel('r', 'r/design', 'screens')).toBe('design/screens')
|
|
122
|
-
expect(resultLabel('r', 'r/design/deep', 'x')).toBe('design/deep/x')
|
|
118
|
+
expect(cumulativeResultsHelper.resultLabel('r', 'r', 'types')).toBe('types')
|
|
119
|
+
expect(cumulativeResultsHelper.resultLabel('r', 'r/design', 'screens')).toBe('design/screens')
|
|
120
|
+
expect(cumulativeResultsHelper.resultLabel('r', 'r/design/deep', 'x')).toBe('design/deep/x')
|
|
123
121
|
})
|
|
124
122
|
|
|
125
123
|
test('a fact is identified by kind, name and where it comes from', () => {
|
|
126
|
-
expect(factKey(user)).toBe(factKey({ ...user, signature: 'other' }))
|
|
127
|
-
expect(factKey(user)).not.toBe(factKey({ ...user, specifier: '@app/other' }))
|
|
124
|
+
expect(cumulativeResultsHelper.factKey(user)).toBe(cumulativeResultsHelper.factKey({ ...user, signature: 'other' }))
|
|
125
|
+
expect(cumulativeResultsHelper.factKey(user)).not.toBe(cumulativeResultsHelper.factKey({ ...user, specifier: '@app/other' }))
|
|
128
126
|
})
|
|
129
127
|
|
|
130
128
|
test('a summary answer renders deterministically and is capped after the fact', () => {
|
|
131
|
-
expect(renderResultSummary({ summary: ' two\nlines ' })).toBe('two lines')
|
|
132
|
-
expect(renderResultSummary({ b: ['x', 'y'], a: 1 })).toBe('a: 1; b: x, y')
|
|
133
|
-
expect(renderResultSummary({ summary: 'word '.repeat(100) }, 40).length).toBeLessThanOrEqual(40)
|
|
129
|
+
expect(cumulativeResultsHelper.renderResultSummary({ summary: ' two\nlines ' })).toBe('two lines')
|
|
130
|
+
expect(cumulativeResultsHelper.renderResultSummary({ b: ['x', 'y'], a: 1 })).toBe('a: 1; b: x, y')
|
|
131
|
+
expect(cumulativeResultsHelper.renderResultSummary({ summary: 'word '.repeat(100) }, 40).length).toBeLessThanOrEqual(40)
|
|
134
132
|
})
|
|
135
133
|
|
|
136
134
|
test('merging declarations accumulates extractors and consumers, later scalars win', () => {
|
|
137
|
-
const merged = mergeResultsSpecs(
|
|
135
|
+
const merged = cumulativeResultsHelper.mergeResultsSpecs(
|
|
138
136
|
{ window: 1, steps: { types: { extractors: ['ts'], full: ['resources'], maxChars: 100 } } },
|
|
139
137
|
null,
|
|
140
138
|
{ window: 3, steps: { types: { extractors: ['ts', 'schema'], full: ['endpoints'], maxChars: 200 } } },
|
package/build/flows.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ShallowFlow } from '@owlmeans/flow';
|
|
2
|
-
/**
|
|
3
|
-
* The lifecycle of one agent run.
|
|
4
|
-
*
|
|
5
|
-
* Read it as "how far did this run get", not "what did it say". Everything conversational happens
|
|
6
|
-
* inside `Working`; the steps exist so a plugin reading `onFinish` can say where a run ended.
|
|
7
|
-
* `Fail` is reachable from every working step and is TERMINAL — see the note on that step.
|
|
8
|
-
*
|
|
9
|
-
* `service` is left as the flow name on every step. A flow step normally binds to a service or an
|
|
10
|
-
* entrypoint, but an agent run is driven by whoever holds the model — there is no second party to
|
|
11
|
-
* hand control to, and inventing one would put a name in the serialized state that nothing
|
|
12
|
-
* resolves.
|
|
13
|
-
*
|
|
14
|
-
* Each working step keeps exactly ONE non-explicit outgoing transition, so `FlowModel.next()`
|
|
15
|
-
* always has an unambiguous answer: that is what lets a driver advance the run without knowing the
|
|
16
|
-
* vocabulary. `Fail` is marked explicit precisely so it never becomes that automatic answer.
|
|
17
|
-
*/
|
|
18
|
-
export declare const agentRunFlow: ShallowFlow;
|
|
19
|
-
/** Every flow this package declares, for a provider to serve. */
|
|
20
|
-
export declare const agentFlows: ShallowFlow[];
|
|
21
|
-
//# sourceMappingURL=flows.d.ts.map
|
package/build/flows.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"flows.d.ts","sourceRoot":"","sources":["../src/flows.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAGjD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,YAAY,EAAE,WA0F1B,CAAA;AAED,iEAAiE;AACjE,eAAO,MAAM,UAAU,EAAE,WAAW,EAAmB,CAAA"}
|
package/build/flows.js
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { AGENT_RUN_FLOW, AgentRunStep, AgentRunTransition } from './consts.js';
|
|
2
|
-
/**
|
|
3
|
-
* The lifecycle of one agent run.
|
|
4
|
-
*
|
|
5
|
-
* Read it as "how far did this run get", not "what did it say". Everything conversational happens
|
|
6
|
-
* inside `Working`; the steps exist so a plugin reading `onFinish` can say where a run ended.
|
|
7
|
-
* `Fail` is reachable from every working step and is TERMINAL — see the note on that step.
|
|
8
|
-
*
|
|
9
|
-
* `service` is left as the flow name on every step. A flow step normally binds to a service or an
|
|
10
|
-
* entrypoint, but an agent run is driven by whoever holds the model — there is no second party to
|
|
11
|
-
* hand control to, and inventing one would put a name in the serialized state that nothing
|
|
12
|
-
* resolves.
|
|
13
|
-
*
|
|
14
|
-
* Each working step keeps exactly ONE non-explicit outgoing transition, so `FlowModel.next()`
|
|
15
|
-
* always has an unambiguous answer: that is what lets a driver advance the run without knowing the
|
|
16
|
-
* vocabulary. `Fail` is marked explicit precisely so it never becomes that automatic answer.
|
|
17
|
-
*/
|
|
18
|
-
export const agentRunFlow = {
|
|
19
|
-
flow: AGENT_RUN_FLOW,
|
|
20
|
-
initialStep: AgentRunStep.Received,
|
|
21
|
-
steps: {
|
|
22
|
-
[AgentRunStep.Received]: {
|
|
23
|
-
index: 0,
|
|
24
|
-
step: AgentRunStep.Received,
|
|
25
|
-
service: AGENT_RUN_FLOW,
|
|
26
|
-
initial: true,
|
|
27
|
-
transitions: {
|
|
28
|
-
[AgentRunTransition.Prepare]: {
|
|
29
|
-
transition: AgentRunTransition.Prepare,
|
|
30
|
-
step: AgentRunStep.Prepared,
|
|
31
|
-
},
|
|
32
|
-
[AgentRunTransition.Fail]: {
|
|
33
|
-
transition: AgentRunTransition.Fail,
|
|
34
|
-
step: AgentRunStep.Failed,
|
|
35
|
-
explicit: true,
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
[AgentRunStep.Prepared]: {
|
|
40
|
-
index: 1,
|
|
41
|
-
step: AgentRunStep.Prepared,
|
|
42
|
-
service: AGENT_RUN_FLOW,
|
|
43
|
-
transitions: {
|
|
44
|
-
[AgentRunTransition.Work]: {
|
|
45
|
-
transition: AgentRunTransition.Work,
|
|
46
|
-
step: AgentRunStep.Working,
|
|
47
|
-
},
|
|
48
|
-
[AgentRunTransition.Fail]: {
|
|
49
|
-
transition: AgentRunTransition.Fail,
|
|
50
|
-
step: AgentRunStep.Failed,
|
|
51
|
-
explicit: true,
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
[AgentRunStep.Working]: {
|
|
56
|
-
index: 2,
|
|
57
|
-
step: AgentRunStep.Working,
|
|
58
|
-
service: AGENT_RUN_FLOW,
|
|
59
|
-
transitions: {
|
|
60
|
-
[AgentRunTransition.Finalize]: {
|
|
61
|
-
transition: AgentRunTransition.Finalize,
|
|
62
|
-
step: AgentRunStep.Finalizing,
|
|
63
|
-
},
|
|
64
|
-
[AgentRunTransition.Fail]: {
|
|
65
|
-
transition: AgentRunTransition.Fail,
|
|
66
|
-
step: AgentRunStep.Failed,
|
|
67
|
-
explicit: true,
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
[AgentRunStep.Finalizing]: {
|
|
72
|
-
index: 3,
|
|
73
|
-
step: AgentRunStep.Finalizing,
|
|
74
|
-
service: AGENT_RUN_FLOW,
|
|
75
|
-
transitions: {
|
|
76
|
-
[AgentRunTransition.Finish]: {
|
|
77
|
-
transition: AgentRunTransition.Finish,
|
|
78
|
-
step: AgentRunStep.Finished,
|
|
79
|
-
},
|
|
80
|
-
[AgentRunTransition.Fail]: {
|
|
81
|
-
transition: AgentRunTransition.Fail,
|
|
82
|
-
step: AgentRunStep.Failed,
|
|
83
|
-
explicit: true,
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
[AgentRunStep.Finished]: {
|
|
88
|
-
index: 4,
|
|
89
|
-
step: AgentRunStep.Finished,
|
|
90
|
-
service: AGENT_RUN_FLOW,
|
|
91
|
-
transitions: {},
|
|
92
|
-
},
|
|
93
|
-
[AgentRunStep.Failed]: {
|
|
94
|
-
index: 5,
|
|
95
|
-
step: AgentRunStep.Failed,
|
|
96
|
-
service: AGENT_RUN_FLOW,
|
|
97
|
-
// Terminal. Nothing resumes a ReAct run — its tool results are side effects already applied
|
|
98
|
-
// to the world, so re-entering it re-applies them. Resumable work is a pipeline.
|
|
99
|
-
transitions: {},
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
/** Every flow this package declares, for a provider to serve. */
|
|
104
|
-
export const agentFlows = [agentRunFlow];
|
|
105
|
-
//# sourceMappingURL=flows.js.map
|
package/build/flows.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"flows.js","sourceRoot":"","sources":["../src/flows.ts"],"names":[],"mappings":"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"}
|