@owlmeans/agent 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 +4 -4
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/agent/SKILL.md +9 -9
- package/build/helpers/compaction/types.d.ts +49 -0
- package/build/helpers/compaction/types.d.ts.map +1 -0
- package/build/helpers/compaction/types.js.map +1 -0
- package/build/helpers/compaction.d.ts +6 -20
- package/build/helpers/compaction.d.ts.map +1 -1
- package/build/helpers/compaction.js +72 -81
- package/build/helpers/compaction.js.map +1 -1
- package/build/helpers/index.d.ts +3 -1
- package/build/helpers/index.d.ts.map +1 -1
- package/build/helpers/index.js.map +1 -1
- package/build/helpers/rolling/types.d.ts +16 -0
- package/build/helpers/rolling/types.d.ts.map +1 -0
- package/build/helpers/rolling/types.js +2 -0
- package/build/helpers/rolling/types.js.map +1 -0
- package/build/helpers/rolling.d.ts +1 -1
- package/build/helpers/rolling.d.ts.map +1 -1
- package/build/helpers/tools/types.d.ts +38 -0
- package/build/helpers/tools/types.d.ts.map +1 -0
- package/build/helpers/tools/types.js +2 -0
- package/build/helpers/{types.js.map → tools/types.js.map} +1 -1
- package/build/helpers/tools.d.ts +6 -26
- package/build/helpers/tools.d.ts.map +1 -1
- package/build/helpers/tools.js +27 -42
- package/build/helpers/tools.js.map +1 -1
- package/build/model.d.ts.map +1 -1
- package/build/model.js +4 -4
- package/build/model.js.map +1 -1
- package/build/pipeline/index.d.ts +2 -1
- package/build/pipeline/index.d.ts.map +1 -1
- package/build/pipeline/results/types.d.ts +139 -0
- package/build/pipeline/results/types.d.ts.map +1 -0
- package/build/pipeline/results/types.js +2 -0
- package/build/pipeline/results/types.js.map +1 -0
- package/build/pipeline/{types.local.d.ts → results/types.local.d.ts} +0 -18
- package/build/pipeline/results/types.local.d.ts.map +1 -0
- package/build/pipeline/results/types.local.js.map +1 -0
- package/build/pipeline/results.d.ts +2 -1
- package/build/pipeline/results.d.ts.map +1 -1
- package/build/pipeline/results.js +22 -22
- package/build/pipeline/results.js.map +1 -1
- package/build/pipeline/runner/types.d.ts +293 -0
- package/build/pipeline/runner/types.d.ts.map +1 -0
- package/build/pipeline/runner/types.js +2 -0
- package/build/pipeline/runner/types.js.map +1 -0
- package/build/pipeline/runner/types.local.d.ts +19 -0
- package/build/pipeline/runner/types.local.d.ts.map +1 -0
- package/build/pipeline/runner/types.local.js +2 -0
- package/build/pipeline/runner/types.local.js.map +1 -0
- package/build/pipeline/runner.d.ts +1 -1
- package/build/pipeline/runner.d.ts.map +1 -1
- package/build/pipeline/runner.js +10 -9
- package/build/pipeline/runner.js.map +1 -1
- package/build/pipeline/types.d.ts +2 -93
- package/build/pipeline/types.d.ts.map +1 -1
- package/build/plugins/export.d.ts +2 -2
- package/build/plugins/export.d.ts.map +1 -1
- package/build/plugins/export.js +2 -2
- package/build/plugins/export.js.map +1 -1
- package/build/plugins/inquiry.d.ts.map +1 -1
- package/build/plugins/inquiry.js +4 -4
- package/build/plugins/inquiry.js.map +1 -1
- package/build/plugins/memory-events.d.ts +3 -1
- package/build/plugins/memory-events.d.ts.map +1 -1
- package/build/plugins/memory-events.js +4 -2
- package/build/plugins/memory-events.js.map +1 -1
- package/build/plugins/memory-graph.d.ts +5 -1
- package/build/plugins/memory-graph.d.ts.map +1 -1
- package/build/plugins/memory-graph.js +4 -2
- package/build/plugins/memory-graph.js.map +1 -1
- package/build/plugins/summarize.d.ts.map +1 -1
- package/build/plugins/summarize.js +2 -2
- package/build/plugins/summarize.js.map +1 -1
- package/build/types.d.ts +5 -3
- package/build/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/helpers/compaction/types.ts +51 -0
- package/src/helpers/compaction.ts +98 -101
- package/src/helpers/index.ts +3 -1
- package/src/helpers/rolling/types.ts +16 -0
- package/src/helpers/rolling.ts +1 -1
- package/src/helpers/tools/types.ts +37 -0
- package/src/helpers/tools.ts +39 -47
- package/src/model.ts +4 -4
- package/src/pipeline/index.ts +2 -1
- package/src/pipeline/{types.local.ts → results/types.local.ts} +0 -21
- package/src/pipeline/results/types.ts +152 -0
- package/src/pipeline/results.ts +25 -24
- package/src/pipeline/runner/types.local.ts +21 -0
- package/src/pipeline/{types.ts → runner/types.ts} +4 -156
- package/src/pipeline/runner.ts +14 -12
- package/src/plugins/export.ts +2 -2
- package/src/plugins/inquiry.ts +4 -4
- package/src/plugins/memory-events.ts +8 -2
- package/src/plugins/memory-graph.ts +8 -2
- package/src/plugins/summarize.ts +2 -2
- package/src/types.ts +4 -4
- package/tests/inquiry.spec.ts +14 -15
- package/tests/pipeline-inquiry.spec.ts +3 -3
- package/tests/plugins.spec.ts +10 -10
- package/tests/summary.spec.ts +8 -8
- package/tests/tools.spec.ts +11 -11
- package/build/helpers/types.d.ts +0 -42
- package/build/helpers/types.d.ts.map +0 -1
- package/build/pipeline/types.local.d.ts.map +0 -1
- package/build/pipeline/types.local.js.map +0 -1
- package/src/helpers/types.ts +0 -43
- /package/build/helpers/{types.js → compaction/types.js} +0 -0
- /package/build/pipeline/{types.local.js → results/types.local.js} +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { CumulativeResultEntry, CumulativeResultFact, PipelineSpec, PipelineState, ResultFactQuery, ResultViewMode, CumulativeResultsSpec, ResultSummarySpec } from '@owlmeans/agent-common'
|
|
2
|
+
import type { CumulativeResults } from '@owlmeans/llm-common'
|
|
3
|
+
import type { CumulativeResultStore } from '../../stores/types.js'
|
|
4
|
+
import type { PipelineEnterMode, PipelineParentRef } from '../runner/types.js'
|
|
5
|
+
|
|
6
|
+
/** What a step tells the results plugin about itself. Every call adds to the last. */
|
|
7
|
+
export interface ResultRecordInput {
|
|
8
|
+
/** Files the step wrote or rewrote, relative to the project root. */
|
|
9
|
+
files?: string[]
|
|
10
|
+
/** Facts the step already knows. Taken as they are, ahead of anything an extractor finds. */
|
|
11
|
+
facts?: CumulativeResultFact[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** One entry a step can see, and how its view shows it. */
|
|
15
|
+
export interface VisibleResultEntry {
|
|
16
|
+
entry: CumulativeResultEntry
|
|
17
|
+
mode: ResultViewMode
|
|
18
|
+
/** Left out of the prompt for BUDGET — named in `view.omitted` — rather than by declaration. */
|
|
19
|
+
dropped?: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The results surface of ONE step: the view to put in its prompt, a query over the facts behind
|
|
24
|
+
* that view for code that wants them, and the way to report what the step produced.
|
|
25
|
+
*/
|
|
26
|
+
export interface StepResults {
|
|
27
|
+
/** The ledger the step's entries belong to. */
|
|
28
|
+
ledger: string
|
|
29
|
+
/** Where the step sits in the ledger — the order key a run composed under it extends. */
|
|
30
|
+
order: readonly number[]
|
|
31
|
+
/** Serializable and frozen; `ExecutionService.withResults(exec, results.view)`. */
|
|
32
|
+
view: CumulativeResults
|
|
33
|
+
/** Every entry visible to the step, oldest first, with how the view shows it. */
|
|
34
|
+
entries: () => readonly VisibleResultEntry[]
|
|
35
|
+
/**
|
|
36
|
+
* Facts visible to the step, narrowed by kind, name and producing step — including those the
|
|
37
|
+
* PROMPT left out for space or by declaration: a budget is about what a model reads, and code
|
|
38
|
+
* asking for a fact is not a model reading a prompt.
|
|
39
|
+
*/
|
|
40
|
+
facts: (query?: ResultFactQuery) => CumulativeResultFact[]
|
|
41
|
+
/** Report files touched and facts known. Read once, when the step finishes. */
|
|
42
|
+
record: (input: ResultRecordInput) => void
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** What a declaration resolver, a seed and a ledger resolver are told about the run. */
|
|
46
|
+
export interface ResultsRunInfo<S extends PipelineState, C> {
|
|
47
|
+
pipeline: string
|
|
48
|
+
spec: PipelineSpec
|
|
49
|
+
runId: string
|
|
50
|
+
scope: string
|
|
51
|
+
entityId?: string
|
|
52
|
+
deps: C
|
|
53
|
+
state: Readonly<S>
|
|
54
|
+
mode: PipelineEnterMode
|
|
55
|
+
parent?: PipelineParentRef
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** What an extractor reads facts from. */
|
|
59
|
+
export interface ResultExtractInput<S extends PipelineState, C> {
|
|
60
|
+
pipeline: string
|
|
61
|
+
runId: string
|
|
62
|
+
step: string
|
|
63
|
+
/** Durable: the run's state, restored from its row on a resume. */
|
|
64
|
+
state: Readonly<S>
|
|
65
|
+
deps: C
|
|
66
|
+
/** Every file the entry answers for — its durable scope and whatever its step recorded. */
|
|
67
|
+
files: readonly string[]
|
|
68
|
+
/** What was recorded as touched on THIS pass — empty on a rebuild. */
|
|
69
|
+
changed: readonly string[]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ResultScopeInput<S extends PipelineState, C> extends Omit<
|
|
73
|
+
ResultExtractInput<S, C>, 'files' | 'changed'
|
|
74
|
+
> {}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Facts from files. DETERMINISTIC — the same inputs give the same facts — and never a model
|
|
78
|
+
* call: an extractor is what makes a fact a fact, and a rebuild after a crash must find exactly
|
|
79
|
+
* what the first pass found.
|
|
80
|
+
*/
|
|
81
|
+
export interface ResultExtractFn<S extends PipelineState, C> { (input: ResultExtractInput<S, C>): Promise<CumulativeResultFact[]> | CumulativeResultFact[] }
|
|
82
|
+
|
|
83
|
+
export interface ResultExtractorSpec<S extends PipelineState, C> {
|
|
84
|
+
/**
|
|
85
|
+
* The files this extractor answers for, recomputed from DURABLE inputs — the state's keys, the
|
|
86
|
+
* file tree — and never from what a step happened to report. It is what a rebuild reads when
|
|
87
|
+
* nothing was recorded, so a step's facts can be found again after the process that ran it died.
|
|
88
|
+
*/
|
|
89
|
+
scope?: (input: ResultScopeInput<S, C>) => Promise<string[]> | string[]
|
|
90
|
+
extract: ResultExtractFn<S, C>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Kept as a type: a union of the bare function and the spec form.
|
|
94
|
+
export type ResultExtractor<S extends PipelineState, C> =
|
|
95
|
+
ResultExtractFn<S, C> | ResultExtractorSpec<S, C>
|
|
96
|
+
|
|
97
|
+
/** Facts known before any step of the run ran. Called on every entry of the run; deterministic. */
|
|
98
|
+
export interface ResultSeed<S extends PipelineState, C> { (run: ResultsRunInfo<S, C>): Promise<CumulativeResultFact[]> | CumulativeResultFact[] }
|
|
99
|
+
|
|
100
|
+
/** Everything a summarize callback needs, including a ready prompt. */
|
|
101
|
+
export interface ResultSummaryRequest<S extends PipelineState, C> extends ResultSummarySpec {
|
|
102
|
+
schema: Record<string, unknown>
|
|
103
|
+
maxChars: number
|
|
104
|
+
pipeline: string
|
|
105
|
+
runId: string
|
|
106
|
+
step: string
|
|
107
|
+
label: string
|
|
108
|
+
facts: readonly CumulativeResultFact[]
|
|
109
|
+
files: readonly string[]
|
|
110
|
+
state: Readonly<S>
|
|
111
|
+
deps: C
|
|
112
|
+
signal: AbortSignal
|
|
113
|
+
/** The instructions, the step's facts and its files, as one deterministic prompt. */
|
|
114
|
+
prompt: string
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Ask a model for a step's summary; return its schema-shaped answer.
|
|
119
|
+
*
|
|
120
|
+
* Typically `request => model.invoke(request.prompt, request.schema, { action })` on a model
|
|
121
|
+
* resolved for `request.role`. A throw is a warning and the entry goes without a summary.
|
|
122
|
+
*/
|
|
123
|
+
export interface ResultSummarizer<S extends PipelineState, C> { (request: ResultSummaryRequest<S, C>): Promise<unknown> }
|
|
124
|
+
|
|
125
|
+
export interface CumulativeResultsPluginOptions<S extends PipelineState, C> {
|
|
126
|
+
alias?: string
|
|
127
|
+
order?: number
|
|
128
|
+
/**
|
|
129
|
+
* The declaration, or a function of the run that returns one — or `null`/`false` to leave THIS
|
|
130
|
+
* run without results. Resolved once, on `enter`.
|
|
131
|
+
*/
|
|
132
|
+
spec:
|
|
133
|
+
| CumulativeResultsSpec
|
|
134
|
+
| ((run: ResultsRunInfo<S, C>) =>
|
|
135
|
+
CumulativeResultsSpec | null | false | undefined
|
|
136
|
+
| Promise<CumulativeResultsSpec | null | false | undefined>)
|
|
137
|
+
/** Named deterministic extractors, referenced by name from `StepResultsSpec.extractors`. */
|
|
138
|
+
extractors?: Record<string, ResultExtractor<S, C>>
|
|
139
|
+
/** Named facts available before any step ran. Visible to every step, in name order. */
|
|
140
|
+
seeds?: Record<string, ResultSeed<S, C>>
|
|
141
|
+
/**
|
|
142
|
+
* Where entries live. A composed pipeline must be given the SAME store as the pipeline it is a
|
|
143
|
+
* step of, or neither sees what the other produced. Default: an in-process memory store of this
|
|
144
|
+
* plugin instance.
|
|
145
|
+
*/
|
|
146
|
+
store?: CumulativeResultStore
|
|
147
|
+
/** Called only for a step whose declaration has a `summary`. */
|
|
148
|
+
summarize?: ResultSummarizer<S, C>
|
|
149
|
+
/** The ledger a run's entries belong to. Default: the parent's, else the root run's id. */
|
|
150
|
+
ledger?: (run: ResultsRunInfo<S, C>) => string
|
|
151
|
+
trace?: (line: string) => void
|
|
152
|
+
}
|
package/src/pipeline/results.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { CumulativeResultSource, DEFAULT_RESULT_SUMMARY_CHARS, DEFAULT_RESULTS_MAX_CHARS, DEFAULT_RESULTS_WINDOW, RESULTS_EVERY_STEP, ResultViewMode,
|
|
2
|
-
import {
|
|
1
|
+
import { CumulativeResultSource, DEFAULT_RESULT_SUMMARY_CHARS, DEFAULT_RESULTS_MAX_CHARS, DEFAULT_RESULTS_WINDOW, RESULTS_EVERY_STEP, ResultViewMode, cumulativeResultsHelper, makePipelineSpecModel, type CumulativeResultEntry, type CumulativeResultFact, type PipelineState, type ResultSummarySpec, type StepResultsSpec } from '@owlmeans/agent-common'
|
|
2
|
+
import { promptRenderHelper } from '@owlmeans/llm'
|
|
3
3
|
import { logger } from '@owlmeans/log'
|
|
4
4
|
import type { CumulativeResults } from '@owlmeans/llm-common'
|
|
5
5
|
import { createMemoryCumulativeResultStore } from '../stores/memory.js'
|
|
6
|
-
import type { PipelinePlugin, PipelineRunContext
|
|
6
|
+
import type { PipelinePlugin, PipelineRunContext } from './runner/types.js'
|
|
7
|
+
import type { StepResults, VisibleResultEntry, CumulativeResultsPluginOptions, ResultExtractFn, ResultExtractor, ResultsRunInfo } from './results/types.js'
|
|
7
8
|
import { SEPARATOR } from './consts.local.js'
|
|
8
9
|
import { CUMULATIVE_RESULTS_PLUGIN, DEFAULT_RESULT_SUMMARY_SCHEMA } from './consts.js'
|
|
9
|
-
import type { EntryParts, Item, Recorded, RunLedger } from './types.local.js'
|
|
10
|
+
import type { EntryParts, Item, Recorded, RunLedger } from './results/types.local.js'
|
|
10
11
|
|
|
11
12
|
const log = logger('agent:pipeline:results')
|
|
12
13
|
|
|
@@ -28,7 +29,7 @@ const dedupe = (facts: readonly CumulativeResultFact[]): CumulativeResultFact[]
|
|
|
28
29
|
const seen = new Set<string>()
|
|
29
30
|
|
|
30
31
|
return facts.filter(fact => {
|
|
31
|
-
const key = factKey(fact)
|
|
32
|
+
const key = cumulativeResultsHelper.factKey(fact)
|
|
32
33
|
if (seen.has(key)) {
|
|
33
34
|
return false
|
|
34
35
|
}
|
|
@@ -71,7 +72,7 @@ const summaryPrompt = (
|
|
|
71
72
|
`The step "${label}" has just finished. For the later steps of the same work, summarize what it `
|
|
72
73
|
+ 'decided or produced that the facts below do not already say. Do not repeat the facts and do not '
|
|
73
74
|
+ `guess at anything not shown. At most ${maxChars} characters.`,
|
|
74
|
-
`# Facts read from the files after the step finished\n${facts.map(renderResultFact).join('\n') || '(none)'}`,
|
|
75
|
+
`# Facts read from the files after the step finished\n${facts.map(cumulativeResultsHelper.renderResultFact).join('\n') || '(none)'}`,
|
|
75
76
|
`# Files the step answers for\n${files.map(file => `- ${file}`).join('\n') || '(none)'}`,
|
|
76
77
|
].join(SEPARATOR)
|
|
77
78
|
|
|
@@ -187,7 +188,7 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
187
188
|
* necessarily run, so what it says cannot be what a step relies on.
|
|
188
189
|
*/
|
|
189
190
|
const visibleTo = (run: RunLedger<C>, step: string): Item[] => {
|
|
190
|
-
const depths = new Map(
|
|
191
|
+
const depths = new Map(makePipelineSpecModel(run.spec).ancestry(step).map(({ step: name, depth }) => [name, depth]))
|
|
191
192
|
const items: Item[] = [
|
|
192
193
|
...run.upstream.map(visible => ({
|
|
193
194
|
entry: visible.entry, mode: visible.mode, explicit: false, dropped: visible.dropped === true,
|
|
@@ -203,7 +204,7 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
return items.sort((a, b) =>
|
|
206
|
-
compareResultOrder(a.entry.order, b.entry.order) || compare(a.entry.label, b.entry.label))
|
|
207
|
+
cumulativeResultsHelper.compareResultOrder(a.entry.order, b.entry.order) || compare(a.entry.label, b.entry.label))
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
const textOf = (item: Item): string =>
|
|
@@ -250,11 +251,11 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
250
251
|
.map(item => item.entry.label)
|
|
251
252
|
const joined = sections.map(section => section.text).join(SEPARATOR)
|
|
252
253
|
const view: CumulativeResults = Object.freeze({
|
|
253
|
-
step: resultLabel(run.ledger, run.runId, step),
|
|
254
|
+
step: cumulativeResultsHelper.resultLabel(run.ledger, run.runId, step),
|
|
254
255
|
sections: Object.freeze(sections) as CumulativeResults['sections'],
|
|
255
256
|
omitted: Object.freeze(omitted) as string[],
|
|
256
257
|
chars: joined.length,
|
|
257
|
-
digest: prefixHash(`${joined}\u0000${omitted.join('\u0000')}`),
|
|
258
|
+
digest: promptRenderHelper.prefixHash(`${joined}\u0000${omitted.join('\u0000')}`),
|
|
258
259
|
})
|
|
259
260
|
const visible: readonly VisibleResultEntry[] = Object.freeze(items.map(item => Object.freeze({
|
|
260
261
|
entry: item.entry, mode: item.mode, ...(item.dropped ? { dropped: true } : {}),
|
|
@@ -347,18 +348,18 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
347
348
|
const owned = new Set<string>()
|
|
348
349
|
for (const item of visibleTo(run, step)) {
|
|
349
350
|
for (const fact of item.entry.facts) {
|
|
350
|
-
owned.add(factKey(fact))
|
|
351
|
+
owned.add(cumulativeResultsHelper.factKey(fact))
|
|
351
352
|
}
|
|
352
353
|
}
|
|
353
354
|
for (const entry of run.entries.values()) {
|
|
354
355
|
if (entry.runId.startsWith(`${run.runId}/${step}`) && anchorOf(run, entry) === step) {
|
|
355
356
|
for (const fact of entry.facts) {
|
|
356
|
-
owned.add(factKey(fact))
|
|
357
|
+
owned.add(cumulativeResultsHelper.factKey(fact))
|
|
357
358
|
}
|
|
358
359
|
}
|
|
359
360
|
}
|
|
360
361
|
|
|
361
|
-
return facts.filter(fact => !owned.has(factKey(fact)))
|
|
362
|
+
return facts.filter(fact => !owned.has(cumulativeResultsHelper.factKey(fact)))
|
|
362
363
|
}
|
|
363
364
|
|
|
364
365
|
/** A step's facts and files, from its durable scope, what it recorded, and its extractors. */
|
|
@@ -374,12 +375,12 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
374
375
|
|
|
375
376
|
const compose = (run: RunLedger<C>, step: string, parts: EntryParts): CumulativeResultEntry => {
|
|
376
377
|
const previous = run.entries.get(keyOf(run.runId, step))
|
|
377
|
-
const label = resultLabel(run.ledger, run.runId, step)
|
|
378
|
+
const label = cumulativeResultsHelper.resultLabel(run.ledger, run.runId, step)
|
|
378
379
|
const source = parts.facts.length === 0 && parts.summary != null
|
|
379
380
|
? CumulativeResultSource.Summarized
|
|
380
381
|
: parts.source
|
|
381
|
-
const facts = sortFacts(parts.facts)
|
|
382
|
-
const rendered = renderResultEntry(
|
|
382
|
+
const facts = cumulativeResultsHelper.sortFacts(parts.facts)
|
|
383
|
+
const rendered = cumulativeResultsHelper.renderResultEntry(
|
|
383
384
|
{ label, source, facts, ...(parts.partial === true ? { partial: true } : {}), ...(parts.summary != null ? { summary: parts.summary } : {}) },
|
|
384
385
|
{
|
|
385
386
|
maxChars: parts.spec?.maxChars ?? run.results.maxEntryChars,
|
|
@@ -424,8 +425,8 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
424
425
|
const mine = orderOf(run, step)
|
|
425
426
|
const earlier = [...run.entries.values()]
|
|
426
427
|
.filter(entry => entry.runId === run.runId && entry.step !== step
|
|
427
|
-
&& compareResultOrder(entry.order, mine) < 0)
|
|
428
|
-
.sort((a, b) => compareResultOrder(a.order, b.order))
|
|
428
|
+
&& cumulativeResultsHelper.compareResultOrder(entry.order, mine) < 0)
|
|
429
|
+
.sort((a, b) => cumulativeResultsHelper.compareResultOrder(a.order, b.order))
|
|
429
430
|
|
|
430
431
|
for (const entry of earlier) {
|
|
431
432
|
const spec = run.results.steps?.[entry.step]
|
|
@@ -437,8 +438,8 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
437
438
|
continue
|
|
438
439
|
}
|
|
439
440
|
const fresh = await extract(run, entry.step, state, entry.files, overlap)
|
|
440
|
-
const freshKeys = new Set(fresh.map(factKey))
|
|
441
|
-
const kept = entry.facts.filter(fact => !freshKeys.has(factKey(fact))
|
|
441
|
+
const freshKeys = new Set(fresh.map(cumulativeResultsHelper.factKey))
|
|
442
|
+
const kept = entry.facts.filter(fact => !freshKeys.has(cumulativeResultsHelper.factKey(fact))
|
|
442
443
|
&& (fact.path == null || !overlap.includes(normalizePath(fact.path))))
|
|
443
444
|
const facts = unowned(run, entry.step, dedupe([...fresh, ...kept]))
|
|
444
445
|
const refreshed = compose(run, entry.step, {
|
|
@@ -466,7 +467,7 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
466
467
|
return undefined
|
|
467
468
|
}
|
|
468
469
|
const maxChars = spec.maxChars ?? DEFAULT_RESULT_SUMMARY_CHARS
|
|
469
|
-
const label = resultLabel(run.ledger, run.runId, step)
|
|
470
|
+
const label = cumulativeResultsHelper.resultLabel(run.ledger, run.runId, step)
|
|
470
471
|
try {
|
|
471
472
|
const answer = await options.summarize({
|
|
472
473
|
...spec,
|
|
@@ -483,7 +484,7 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
483
484
|
signal: ctx.signal,
|
|
484
485
|
prompt: summaryPrompt(spec, label, facts, files, maxChars),
|
|
485
486
|
})
|
|
486
|
-
const text = renderResultSummary(answer, maxChars)
|
|
487
|
+
const text = cumulativeResultsHelper.renderResultSummary(answer, maxChars)
|
|
487
488
|
|
|
488
489
|
return text !== '' ? text : undefined
|
|
489
490
|
} catch (e) {
|
|
@@ -516,14 +517,14 @@ export const cumulativeResultsPlugin = <S extends PipelineState, C>(
|
|
|
516
517
|
}
|
|
517
518
|
|
|
518
519
|
const parent = event.parent?.results
|
|
519
|
-
const ledger = options.ledger?.(info) ?? parent?.ledger ?? rootRunOf(event.runId)
|
|
520
|
+
const ledger = options.ledger?.(info) ?? parent?.ledger ?? cumulativeResultsHelper.rootRunOf(event.runId)
|
|
520
521
|
const run: RunLedger<C> = {
|
|
521
522
|
results: declared,
|
|
522
523
|
spec: event.spec,
|
|
523
524
|
runId: event.runId,
|
|
524
525
|
ledger,
|
|
525
526
|
trail: parent != null ? [...parent.order] : [],
|
|
526
|
-
index: new Map(
|
|
527
|
+
index: new Map(makePipelineSpecModel(event.spec).orderSteps().map((step, at) => [step, at + 1])),
|
|
527
528
|
entries: new Map(),
|
|
528
529
|
upstream: parent != null ? parent.entries() : [],
|
|
529
530
|
seeds: [],
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BaseCheckpointSaver } from '@langchain/langgraph'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The graph builder, seen loosely.
|
|
5
|
+
*
|
|
6
|
+
* `StateGraph`'s node names are a generic parameter that only a literal-typed builder chain can
|
|
7
|
+
* satisfy, and a pipeline's nodes come from data. The precision belongs at THIS package's public
|
|
8
|
+
* boundary — `PipelineSpec`, `PipelineStep`, `PipelineModel` are all exact — not in the three lines
|
|
9
|
+
* that hand LangGraph a name it will look up in a map either way.
|
|
10
|
+
*/
|
|
11
|
+
export interface LooseGraph {
|
|
12
|
+
addNode: (
|
|
13
|
+
name: string,
|
|
14
|
+
fn: (state: unknown) => Promise<Record<string, unknown>>,
|
|
15
|
+
options?: Record<string, unknown>,
|
|
16
|
+
) => LooseGraph
|
|
17
|
+
addEdge: (start: string | string[], end: string) => LooseGraph
|
|
18
|
+
compile: (options?: { checkpointer?: BaseCheckpointSaver }) => {
|
|
19
|
+
invoke: (input: unknown, config?: Record<string, unknown>) => Promise<unknown>
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { BaseCheckpointSaver } from '@langchain/langgraph'
|
|
2
|
-
import type {
|
|
3
|
-
import type {
|
|
4
|
-
import type { PipelineRunStore
|
|
2
|
+
import type { PipelineProgress, PipelineRun, PipelineRunInquiry, PipelineRunStatus, PipelineSpec, PipelineState } from '@owlmeans/agent-common'
|
|
3
|
+
import type { Inquiry, InquiryAnswer } from '@owlmeans/llm-common'
|
|
4
|
+
import type { PipelineRunStore } from '../../stores/types.js'
|
|
5
|
+
import type { StepResults } from '../results/types.js'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* What a step is handed while it runs.
|
|
@@ -72,45 +73,6 @@ export interface PipelineRunContext<S extends PipelineState, C> {
|
|
|
72
73
|
results?: StepResults
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
/** What a step tells the results plugin about itself. Every call adds to the last. */
|
|
76
|
-
export interface ResultRecordInput {
|
|
77
|
-
/** Files the step wrote or rewrote, relative to the project root. */
|
|
78
|
-
files?: string[]
|
|
79
|
-
/** Facts the step already knows. Taken as they are, ahead of anything an extractor finds. */
|
|
80
|
-
facts?: CumulativeResultFact[]
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** One entry a step can see, and how its view shows it. */
|
|
84
|
-
export interface VisibleResultEntry {
|
|
85
|
-
entry: CumulativeResultEntry
|
|
86
|
-
mode: ResultViewMode
|
|
87
|
-
/** Left out of the prompt for BUDGET — named in `view.omitted` — rather than by declaration. */
|
|
88
|
-
dropped?: boolean
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* The results surface of ONE step: the view to put in its prompt, a query over the facts behind
|
|
93
|
-
* that view for code that wants them, and the way to report what the step produced.
|
|
94
|
-
*/
|
|
95
|
-
export interface StepResults {
|
|
96
|
-
/** The ledger the step's entries belong to. */
|
|
97
|
-
ledger: string
|
|
98
|
-
/** Where the step sits in the ledger — the order key a run composed under it extends. */
|
|
99
|
-
order: readonly number[]
|
|
100
|
-
/** Serializable and frozen; `ExecutionService.withResults(exec, results.view)`. */
|
|
101
|
-
view: CumulativeResults
|
|
102
|
-
/** Every entry visible to the step, oldest first, with how the view shows it. */
|
|
103
|
-
entries: () => readonly VisibleResultEntry[]
|
|
104
|
-
/**
|
|
105
|
-
* Facts visible to the step, narrowed by kind, name and producing step — including those the
|
|
106
|
-
* PROMPT left out for space or by declaration: a budget is about what a model reads, and code
|
|
107
|
-
* asking for a fact is not a model reading a prompt.
|
|
108
|
-
*/
|
|
109
|
-
facts: (query?: ResultFactQuery) => CumulativeResultFact[]
|
|
110
|
-
/** Report files touched and facts known. Read once, when the step finishes. */
|
|
111
|
-
record: (input: ResultRecordInput) => void
|
|
112
|
-
}
|
|
113
|
-
|
|
114
76
|
/**
|
|
115
77
|
* The composing step of a parent pipeline, as a run composed under it (`asStep`) sees it —
|
|
116
78
|
* read-only by construction: a composed run may learn where it sits, never write its parent.
|
|
@@ -350,117 +312,3 @@ export interface PipelineModel<S extends PipelineState, C> {
|
|
|
350
312
|
step: string, mapping: PipelineStepMapping<S, PS>
|
|
351
313
|
) => PipelineStep<PS, C>
|
|
352
314
|
}
|
|
353
|
-
|
|
354
|
-
/** What a declaration resolver, a seed and a ledger resolver are told about the run. */
|
|
355
|
-
export interface ResultsRunInfo<S extends PipelineState, C> {
|
|
356
|
-
pipeline: string
|
|
357
|
-
spec: PipelineSpec
|
|
358
|
-
runId: string
|
|
359
|
-
scope: string
|
|
360
|
-
entityId?: string
|
|
361
|
-
deps: C
|
|
362
|
-
state: Readonly<S>
|
|
363
|
-
mode: PipelineEnterMode
|
|
364
|
-
parent?: PipelineParentRef
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
/** What an extractor reads facts from. */
|
|
368
|
-
export interface ResultExtractInput<S extends PipelineState, C> {
|
|
369
|
-
pipeline: string
|
|
370
|
-
runId: string
|
|
371
|
-
step: string
|
|
372
|
-
/** Durable: the run's state, restored from its row on a resume. */
|
|
373
|
-
state: Readonly<S>
|
|
374
|
-
deps: C
|
|
375
|
-
/** Every file the entry answers for — its durable scope and whatever its step recorded. */
|
|
376
|
-
files: readonly string[]
|
|
377
|
-
/** What was recorded as touched on THIS pass — empty on a rebuild. */
|
|
378
|
-
changed: readonly string[]
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
export type ResultScopeInput<S extends PipelineState, C> = Omit<
|
|
382
|
-
ResultExtractInput<S, C>, 'files' | 'changed'
|
|
383
|
-
>
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Facts from files. DETERMINISTIC — the same inputs give the same facts — and never a model
|
|
387
|
-
* call: an extractor is what makes a fact a fact, and a rebuild after a crash must find exactly
|
|
388
|
-
* what the first pass found.
|
|
389
|
-
*/
|
|
390
|
-
export type ResultExtractFn<S extends PipelineState, C> = (
|
|
391
|
-
input: ResultExtractInput<S, C>,
|
|
392
|
-
) => Promise<CumulativeResultFact[]> | CumulativeResultFact[]
|
|
393
|
-
|
|
394
|
-
export interface ResultExtractorSpec<S extends PipelineState, C> {
|
|
395
|
-
/**
|
|
396
|
-
* The files this extractor answers for, recomputed from DURABLE inputs — the state's keys, the
|
|
397
|
-
* file tree — and never from what a step happened to report. It is what a rebuild reads when
|
|
398
|
-
* nothing was recorded, so a step's facts can be found again after the process that ran it died.
|
|
399
|
-
*/
|
|
400
|
-
scope?: (input: ResultScopeInput<S, C>) => Promise<string[]> | string[]
|
|
401
|
-
extract: ResultExtractFn<S, C>
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
export type ResultExtractor<S extends PipelineState, C> =
|
|
405
|
-
ResultExtractFn<S, C> | ResultExtractorSpec<S, C>
|
|
406
|
-
|
|
407
|
-
/** Facts known before any step of the run ran. Called on every entry of the run; deterministic. */
|
|
408
|
-
export type ResultSeed<S extends PipelineState, C> = (
|
|
409
|
-
run: ResultsRunInfo<S, C>,
|
|
410
|
-
) => Promise<CumulativeResultFact[]> | CumulativeResultFact[]
|
|
411
|
-
|
|
412
|
-
/** Everything a summarize callback needs, including a ready prompt. */
|
|
413
|
-
export interface ResultSummaryRequest<S extends PipelineState, C> extends ResultSummarySpec {
|
|
414
|
-
schema: Record<string, unknown>
|
|
415
|
-
maxChars: number
|
|
416
|
-
pipeline: string
|
|
417
|
-
runId: string
|
|
418
|
-
step: string
|
|
419
|
-
label: string
|
|
420
|
-
facts: readonly CumulativeResultFact[]
|
|
421
|
-
files: readonly string[]
|
|
422
|
-
state: Readonly<S>
|
|
423
|
-
deps: C
|
|
424
|
-
signal: AbortSignal
|
|
425
|
-
/** The instructions, the step's facts and its files, as one deterministic prompt. */
|
|
426
|
-
prompt: string
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/**
|
|
430
|
-
* Ask a model for a step's summary; return its schema-shaped answer.
|
|
431
|
-
*
|
|
432
|
-
* Typically `request => model.invoke(request.prompt, request.schema, { action })` on a model
|
|
433
|
-
* resolved for `request.role`. A throw is a warning and the entry goes without a summary.
|
|
434
|
-
*/
|
|
435
|
-
export type ResultSummarizer<S extends PipelineState, C> = (
|
|
436
|
-
request: ResultSummaryRequest<S, C>,
|
|
437
|
-
) => Promise<unknown>
|
|
438
|
-
|
|
439
|
-
export interface CumulativeResultsPluginOptions<S extends PipelineState, C> {
|
|
440
|
-
alias?: string
|
|
441
|
-
order?: number
|
|
442
|
-
/**
|
|
443
|
-
* The declaration, or a function of the run that returns one — or `null`/`false` to leave THIS
|
|
444
|
-
* run without results. Resolved once, on `enter`.
|
|
445
|
-
*/
|
|
446
|
-
spec:
|
|
447
|
-
| CumulativeResultsSpec
|
|
448
|
-
| ((run: ResultsRunInfo<S, C>) =>
|
|
449
|
-
CumulativeResultsSpec | null | false | undefined
|
|
450
|
-
| Promise<CumulativeResultsSpec | null | false | undefined>)
|
|
451
|
-
/** Named deterministic extractors, referenced by name from `StepResultsSpec.extractors`. */
|
|
452
|
-
extractors?: Record<string, ResultExtractor<S, C>>
|
|
453
|
-
/** Named facts available before any step ran. Visible to every step, in name order. */
|
|
454
|
-
seeds?: Record<string, ResultSeed<S, C>>
|
|
455
|
-
/**
|
|
456
|
-
* Where entries live. A composed pipeline must be given the SAME store as the pipeline it is a
|
|
457
|
-
* step of, or neither sees what the other produced. Default: an in-process memory store of this
|
|
458
|
-
* plugin instance.
|
|
459
|
-
*/
|
|
460
|
-
store?: CumulativeResultStore
|
|
461
|
-
/** Called only for a step whose declaration has a `summary`. */
|
|
462
|
-
summarize?: ResultSummarizer<S, C>
|
|
463
|
-
/** The ledger a run's entries belong to. Default: the parent's, else the root run's id. */
|
|
464
|
-
ledger?: (run: ResultsRunInfo<S, C>) => string
|
|
465
|
-
trace?: (line: string) => void
|
|
466
|
-
}
|
package/src/pipeline/runner.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Annotation, END, START, StateGraph } from '@langchain/langgraph'
|
|
2
|
-
import { AgentRunStateError, DEFAULT_MAX_STATE_CHARS, INQUIRY_ANSWERS_KEY, PipelineNotIdempotentError, PipelineNotResumableError, PipelineRunStatus, PipelineSpecError, PipelineStateTooLargeError, PipelineVersionError,
|
|
3
|
-
import { DEFAULT_INQUIRY_ANSWER_CHARS,
|
|
2
|
+
import { AgentRunStateError, DEFAULT_MAX_STATE_CHARS, INQUIRY_ANSWERS_KEY, PipelineNotIdempotentError, PipelineNotResumableError, PipelineRunStatus, PipelineSpecError, PipelineStateTooLargeError, PipelineVersionError, type PipelineProgress, type PipelineRun, type PipelineRunInquiry, type PipelineSpec, type PipelineState, type PipelineStepSpec, makePipelineSpecModel } from '@owlmeans/agent-common'
|
|
3
|
+
import { DEFAULT_INQUIRY_ANSWER_CHARS, type InquiryAnswer, inquiryHelper } from '@owlmeans/llm-common'
|
|
4
4
|
import { logger } from '@owlmeans/log'
|
|
5
5
|
import type {
|
|
6
6
|
PipelineEnterMode, PipelineInvokeArgs, PipelineModel, PipelineOptions, PipelineParentRef,
|
|
7
7
|
PipelinePlugin, PipelineResult, PipelineRunContext, PipelineStep, PipelineStepContribution,
|
|
8
|
-
PipelineStepMapping,
|
|
9
|
-
} from './types.js'
|
|
8
|
+
PipelineStepMapping,
|
|
9
|
+
} from './runner/types.js'
|
|
10
|
+
import type { StepResults } from './results/types.js'
|
|
10
11
|
import { DEFAULT_PIPELINE_PLUGIN_ORDER, MAX_INQUIRY_ROUNDS } from './consts.local.js'
|
|
11
|
-
import type { LooseGraph } from './types.local.js'
|
|
12
|
+
import type { LooseGraph } from './runner/types.local.js'
|
|
12
13
|
|
|
13
14
|
const log = logger('agent:pipeline')
|
|
14
15
|
|
|
@@ -78,7 +79,8 @@ const answersIn = (state: unknown, key: string): Record<string, InquiryAnswer> =
|
|
|
78
79
|
export const makePipeline = <S extends PipelineState, C>(
|
|
79
80
|
spec: PipelineSpec, options: PipelineOptions<S, C>,
|
|
80
81
|
): PipelineModel<S, C> => {
|
|
81
|
-
|
|
82
|
+
const specModel = makePipelineSpecModel(spec)
|
|
83
|
+
specModel.validate()
|
|
82
84
|
|
|
83
85
|
const handlers = new Map<string, PipelineStep<S, C>>()
|
|
84
86
|
const faults: string[] = []
|
|
@@ -100,7 +102,7 @@ export const makePipeline = <S extends PipelineState, C>(
|
|
|
100
102
|
throw new PipelineSpecError(`${spec.alias}: ${faults.join('; ')}`)
|
|
101
103
|
}
|
|
102
104
|
|
|
103
|
-
const order =
|
|
105
|
+
const order = specModel.orderSteps()
|
|
104
106
|
const total = order.length
|
|
105
107
|
const runs = options.runs
|
|
106
108
|
const maxStateChars = options.maxStateChars ?? DEFAULT_MAX_STATE_CHARS
|
|
@@ -145,7 +147,7 @@ export const makePipeline = <S extends PipelineState, C>(
|
|
|
145
147
|
|
|
146
148
|
/** The copy of an answer this pipeline's STATE is allowed to hold. */
|
|
147
149
|
const forState = (answer: InquiryAnswer): InquiryAnswer =>
|
|
148
|
-
stateAnswerOf(capAnswer(answer, maxAnswerChars))
|
|
150
|
+
inquiryHelper.stateAnswerOf(inquiryHelper.capAnswer(answer, maxAnswerChars))
|
|
149
151
|
|
|
150
152
|
/**
|
|
151
153
|
* Fold every source of answers into the live state, later sources winning per id.
|
|
@@ -321,7 +323,7 @@ export const makePipeline = <S extends PipelineState, C>(
|
|
|
321
323
|
: null
|
|
322
324
|
|
|
323
325
|
if (answer != null) {
|
|
324
|
-
const capped = capAnswer({ ...answer, inquiryId: inquiry.id }, maxAnswerChars)
|
|
326
|
+
const capped = inquiryHelper.capAnswer({ ...answer, inquiryId: inquiry.id }, maxAnswerChars)
|
|
325
327
|
// The state keeps the DECISION and a short excerpt of any prose; the step is handed the
|
|
326
328
|
// whole answer. A state is scalars and keys, and two long answers would spend a
|
|
327
329
|
// pipeline's whole state budget on text nothing replays from.
|
|
@@ -333,7 +335,7 @@ export const makePipeline = <S extends PipelineState, C>(
|
|
|
333
335
|
// person has already answered to be asked again on the next entry.
|
|
334
336
|
await ctx.mark({
|
|
335
337
|
[answersKey]: {
|
|
336
|
-
...answersIn(live, answersKey), [inquiry.id]: stateAnswerOf(capped),
|
|
338
|
+
...answersIn(live, answersKey), [inquiry.id]: inquiryHelper.stateAnswerOf(capped),
|
|
337
339
|
},
|
|
338
340
|
} as Partial<S>)
|
|
339
341
|
|
|
@@ -765,9 +767,9 @@ export const makePipeline = <S extends PipelineState, C>(
|
|
|
765
767
|
|
|
766
768
|
let completed = [...existing.completed]
|
|
767
769
|
if (args.from != null) {
|
|
768
|
-
const rerun =
|
|
770
|
+
const rerun = specModel.descendants(args.from)
|
|
769
771
|
const blocked = rerun.filter(step =>
|
|
770
|
-
completed.includes(step) &&
|
|
772
|
+
completed.includes(step) && specModel.stepOf(step)?.nonIdempotent === true)
|
|
771
773
|
if (blocked.length > 0 && args.force !== true) {
|
|
772
774
|
throw new PipelineNotIdempotentError(`${runId}:${blocked.join(',')}`)
|
|
773
775
|
}
|
package/src/plugins/export.ts
CHANGED
|
@@ -4,11 +4,11 @@ export { summarizePlugin } from './summarize.js'
|
|
|
4
4
|
export { SUMMARIZE_PLUGIN } from './consts.js'
|
|
5
5
|
export type { SummarizeOptions } from './types.js'
|
|
6
6
|
|
|
7
|
-
export { memoryGraph, memoryGraphPlugin } from './memory-graph.js'
|
|
7
|
+
export { makeMemoryGraphApi, memoryGraph, memoryGraphPlugin } from './memory-graph.js'
|
|
8
8
|
export { DEFAULT_FOLLOW, MEMORY_GRAPH_PLUGIN } from './consts.js'
|
|
9
9
|
export type { MemoryGraphApi, MemoryGraphOptions } from './types.js'
|
|
10
10
|
|
|
11
|
-
export { memoryEvents, memoryEventsPlugin } from './memory-events.js'
|
|
11
|
+
export { makeMemoryEventsApi, memoryEvents, memoryEventsPlugin } from './memory-events.js'
|
|
12
12
|
export { DEFAULT_MEMORY_EVENT_CHARS, MEMORY_EVENTS_PLUGIN } from './consts.js'
|
|
13
13
|
export type { MemoryEventsApi, MemoryEventsOptions } from './types.js'
|
|
14
14
|
|
package/src/plugins/inquiry.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { tool } from '@langchain/core/tools'
|
|
2
2
|
import { IdStyle, createIdOfLength } from '@owlmeans/basic-ids'
|
|
3
|
-
import { DEFAULT_INQUIRY_OPTIONS, InquiryKind,
|
|
3
|
+
import { DEFAULT_INQUIRY_OPTIONS, InquiryKind, type Inquiry, inquiryHelper } from '@owlmeans/llm-common'
|
|
4
4
|
import { InquiryDeclined, InquiryUnavailable } from '@owlmeans/llm'
|
|
5
|
-
import { toErrorResponse } from '../helpers/tools.js'
|
|
6
5
|
import type { AgentPlugin, AgentToolSet } from '../types.js'
|
|
7
6
|
import { ASK_USER_TOOL, INQUIRY_PLUGIN } from './consts.js'
|
|
8
7
|
import type { AskUserArgs } from './types.local.js'
|
|
9
8
|
import type { InquiryPluginOptions } from './types.js'
|
|
9
|
+
import { toolHelper } from '../helpers/tools.js'
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -78,7 +78,7 @@ export const inquiryPlugin = (options: InquiryPluginOptions = {}): AgentPlugin =
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
return JSON.stringify(capAnswer(answer, options.maxAnswerChars))
|
|
81
|
+
return JSON.stringify(inquiryHelper.capAnswer(answer, options.maxAnswerChars))
|
|
82
82
|
} catch (e) {
|
|
83
83
|
if (e instanceof InquiryUnavailable) {
|
|
84
84
|
// The one throw. A channel that has gone cannot be argued with, and containing it
|
|
@@ -91,7 +91,7 @@ export const inquiryPlugin = (options: InquiryPluginOptions = {}): AgentPlugin =
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
return toErrorResponse(e)
|
|
94
|
+
return toolHelper.toErrorResponse(e)
|
|
95
95
|
}
|
|
96
96
|
},
|
|
97
97
|
{
|
|
@@ -16,7 +16,7 @@ import type { MemoryEventsApi, MemoryEventsOptions } from './types.js'
|
|
|
16
16
|
* The bound is per scope, and pruning is per scope, so a busy subject cannot evict a quiet one's
|
|
17
17
|
* whole history.
|
|
18
18
|
*/
|
|
19
|
-
export const
|
|
19
|
+
export const makeMemoryEventsApi = (
|
|
20
20
|
store: MemoryEventStore,
|
|
21
21
|
options: Pick<MemoryEventsOptions, 'limit' | 'maxEventChars'> = {},
|
|
22
22
|
): MemoryEventsApi => {
|
|
@@ -35,7 +35,7 @@ export const memoryEvents = (
|
|
|
35
35
|
export const memoryEventsPlugin = (options: MemoryEventsOptions = {}): AgentPlugin => {
|
|
36
36
|
const { store, window = DEFAULT_EVENT_WINDOW, tools: withTools = true } = options
|
|
37
37
|
const scopeOf = (run: AgentRun): string => options.scope?.(run) ?? run.conversation.scope
|
|
38
|
-
const api = (): MemoryEventsApi | null => store == null ? null :
|
|
38
|
+
const api = (): MemoryEventsApi | null => store == null ? null : makeMemoryEventsApi(store, options)
|
|
39
39
|
|
|
40
40
|
return {
|
|
41
41
|
alias: MEMORY_EVENTS_PLUGIN,
|
|
@@ -105,3 +105,9 @@ export const memoryEventsPlugin = (options: MemoryEventsOptions = {}): AgentPlug
|
|
|
105
105
|
},
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
|
|
109
|
+
/** @deprecated compat:factory-refactor — use `makeMemoryEventsApi(…)` */
|
|
110
|
+
export const memoryEvents = (
|
|
111
|
+
store: MemoryEventStore,
|
|
112
|
+
options: Pick<MemoryEventsOptions, 'limit' | 'maxEventChars'> = {},
|
|
113
|
+
): MemoryEventsApi => makeMemoryEventsApi(store, options)
|