@owlmeans/agent 0.1.18-rc.52 → 0.1.18-rc.54
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 +7 -5
- package/agent-meta/manifest.json +59 -4
- package/agent-meta/skills/agent/SKILL.md +32 -169
- package/agent-meta/skills/agent/parts/cumulative-results.md +62 -0
- package/agent-meta/skills/agent/parts/pipelines.md +113 -0
- package/agent-meta/skills/agent/parts/testing.md +19 -0
- package/build/model.d.ts.map +1 -1
- package/build/model.js +53 -11
- package/build/model.js.map +1 -1
- package/build/plugins/summarize.d.ts +1 -1
- package/build/plugins/summarize.js +1 -1
- package/build/types.d.ts +12 -5
- package/build/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/model.ts +60 -16
- package/src/plugins/summarize.ts +1 -1
- package/src/types.ts +12 -4
- package/tests/_tools/model.ts +12 -3
- package/tests/agent.spec.ts +87 -9
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ import { makeAgentModel } from '@owlmeans/agent'
|
|
|
14
14
|
const agent = makeAgentModel({
|
|
15
15
|
exec, // an @owlmeans/llm Execution — its prompt policy is the persona
|
|
16
16
|
tools, // { [name]: StructuredToolInterface }
|
|
17
|
-
context: [projectBrief], //
|
|
17
|
+
context: [projectBrief], // run context; lands in PromptBlock.Context, the project message
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
const result = await agent.invoke('rename the dashboard header')
|
|
@@ -45,9 +45,11 @@ with no agent at all, so a pipeline helper writes to the same store an agent rea
|
|
|
45
45
|
|
|
46
46
|
## Things worth knowing before you change it
|
|
47
47
|
|
|
48
|
-
**Contributed context goes to `PromptBlock.Context` and nowhere else.**
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
**Contributed context goes to `PromptBlock.Context` and nowhere else.** It travels in the project
|
|
49
|
+
message after the system, so the system region — role, skills, packages — stays byte-identical for
|
|
50
|
+
every run of a persona. Run material anywhere in the system invalidates the prefix every call
|
|
51
|
+
sharing that persona pays for. Each round caches the opening (`loopCache` of the model's provider
|
|
52
|
+
plugin) and lets the growing conversation be read back from the round before.
|
|
51
53
|
|
|
52
54
|
**`toolHelper.safeInvokeTool` must never throw.** A rejected LangGraph task aborts the whole superstep: every
|
|
53
55
|
sibling tool call in the same parallel batch dies with it, discarding work they had already
|
|
@@ -84,7 +86,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
84
86
|
your project's skill store (`.agents/skills/`):
|
|
85
87
|
|
|
86
88
|
```sh
|
|
87
|
-
npx @owlmeans/agent-skills@^0.1.18-rc.
|
|
89
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.57
|
|
88
90
|
```
|
|
89
91
|
|
|
90
92
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schemaVersion":
|
|
2
|
+
"schemaVersion": 3,
|
|
3
3
|
"package": "@owlmeans/agent",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-10-
|
|
4
|
+
"version": "0.1.18-rc.54",
|
|
5
|
+
"generatedAt": "2026-10-20T23:19:58.631Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -10,7 +10,62 @@
|
|
|
10
10
|
"name": "agent",
|
|
11
11
|
"category": "package-specific",
|
|
12
12
|
"file": "skills/agent/SKILL.md",
|
|
13
|
-
"canonicalPath": ".agents/skills/agent/SKILL.md"
|
|
13
|
+
"canonicalPath": ".agents/skills/agent/SKILL.md",
|
|
14
|
+
"parts": [
|
|
15
|
+
{
|
|
16
|
+
"name": "cumulative-results",
|
|
17
|
+
"file": "skills/agent/parts/cumulative-results.md",
|
|
18
|
+
"description": "Cumulative pipeline results — deterministic extractors, the ledger and its rebuild, how a step's view is cut, refresh, model summaries, composed runs and seeds.",
|
|
19
|
+
"purposes": [
|
|
20
|
+
"agent",
|
|
21
|
+
"job"
|
|
22
|
+
],
|
|
23
|
+
"mentions": [
|
|
24
|
+
"cumulativeResultsPlugin",
|
|
25
|
+
"CUMULATIVE_RESULTS_PLUGIN",
|
|
26
|
+
"CumulativeResultStore",
|
|
27
|
+
"CumulativeResultFact",
|
|
28
|
+
"DEFAULT_RESULT_SUMMARY_SCHEMA",
|
|
29
|
+
"ctx.results",
|
|
30
|
+
"withResults"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "pipelines",
|
|
35
|
+
"file": "skills/agent/parts/pipelines.md",
|
|
36
|
+
"description": "Resumable pipelines over a checkpointed StateGraph — steps and edges, the PipelinePlugin seam, and the rules for run rows, step guards, state size, failures and retries.",
|
|
37
|
+
"purposes": [
|
|
38
|
+
"agent",
|
|
39
|
+
"job",
|
|
40
|
+
"state"
|
|
41
|
+
],
|
|
42
|
+
"mentions": [
|
|
43
|
+
"makePipeline",
|
|
44
|
+
"PipelineSpec",
|
|
45
|
+
"PipelinePlugin",
|
|
46
|
+
"asStep",
|
|
47
|
+
"skipWhen",
|
|
48
|
+
"nonIdempotent",
|
|
49
|
+
"makeCheckpointSaver",
|
|
50
|
+
"PipelineRunStore",
|
|
51
|
+
"CheckpointStore",
|
|
52
|
+
"maxStateChars",
|
|
53
|
+
"ctx.mark",
|
|
54
|
+
"@owlmeans/agent/pipeline"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "testing",
|
|
59
|
+
"file": "skills/agent/parts/testing.md",
|
|
60
|
+
"description": "Unit tests of agents and pipelines with a scripted model double and files kept in deps.",
|
|
61
|
+
"purposes": [
|
|
62
|
+
"test"
|
|
63
|
+
],
|
|
64
|
+
"mentions": [
|
|
65
|
+
"FakeStreamingChatModel"
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
]
|
|
14
69
|
}
|
|
15
70
|
]
|
|
16
71
|
}
|
|
@@ -8,7 +8,7 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/agent
|
|
9
9
|
|
|
10
10
|
**Layer:** Cross-cutting domain
|
|
11
|
-
**Install:** `"@owlmeans/agent": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/agent": "^0.1.18-rc.54"` in `dependencies`, plus the `@langchain/core` and
|
|
12
12
|
`@langchain/langgraph` **peers**
|
|
13
13
|
|
|
14
14
|
The agent runtime. Contracts live in `@owlmeans/agent-common`.
|
|
@@ -19,7 +19,7 @@ The agent runtime. Contracts live in `@owlmeans/agent-common`.
|
|
|
19
19
|
|---|---|
|
|
20
20
|
| `makeAgentModel(options)` | An agent over the LangGraph functional API: `invoke`, `use`, `conversation`. |
|
|
21
21
|
| `makePipeline(spec, options)` | A resumable state machine over a checkpointed LangGraph `StateGraph`: `invoke`, `resume`, `snapshot`, `asStep`. `options.plugins` seats `PipelinePlugin`s. |
|
|
22
|
-
| `cumulativeResultsPlugin(options)` · `CUMULATIVE_RESULTS_PLUGIN` · `DEFAULT_RESULT_SUMMARY_SCHEMA` | CUMULATIVE PIPELINE RESULTS — tells every step what its predecessors produced; see
|
|
22
|
+
| `cumulativeResultsPlugin(options)` · `CUMULATIVE_RESULTS_PLUGIN` · `DEFAULT_RESULT_SUMMARY_SCHEMA` | CUMULATIVE PIPELINE RESULTS — tells every step what its predecessors produced; see the `cumulative-results` part. |
|
|
23
23
|
| `PipelinePlugin` and its events, `StepResults`, `PipelineParentRef` | The pipeline plugin seam (types, from `./pipeline`). |
|
|
24
24
|
| `makeCheckpointSaver(store)` | A `BaseCheckpointSaver` over the `CheckpointStore` port. |
|
|
25
25
|
| `makeAgentsService(options?, alias?)` · `appendAgentsService(ctx, options?, alias?)` · `agentServiceApi(options, self)` | The service, and its half without `createService` for composition. |
|
|
@@ -36,124 +36,6 @@ The agent runtime. Contracts live in `@owlmeans/agent-common`.
|
|
|
36
36
|
|
|
37
37
|
Subpath exports: `./plugins`, `./helpers`, `./stores`, `./pipeline`, `./checkpoint`.
|
|
38
38
|
|
|
39
|
-
## Pipelines
|
|
40
|
-
|
|
41
|
-
A pipeline is a **state machine over named steps** whose position is persisted at every step
|
|
42
|
-
boundary, so a run killed anywhere continues from the step it stopped at rather than from zero.
|
|
43
|
-
|
|
44
|
-
```ts
|
|
45
|
-
const spec: PipelineSpec = {
|
|
46
|
-
alias: 'vib:story:design', version: 1,
|
|
47
|
-
steps: [
|
|
48
|
-
{ step: 'screens' },
|
|
49
|
-
{ step: 'ux', after: ['screens'] },
|
|
50
|
-
{ step: 'data', after: ['screens'] }, // runs BESIDE `ux`
|
|
51
|
-
{ step: 'persist', after: ['ux', 'data'] }, // joins BOTH
|
|
52
|
-
],
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const pipeline = makePipeline<State, Deps>(spec, { steps, runs, checkpointer, fatal })
|
|
56
|
-
await pipeline.invoke(seed, { runId, deps, scope: projectId })
|
|
57
|
-
await pipeline.resume(runId, { deps, from: 'data' })
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
**`StateGraph`, not the functional API.** A resume must be able to name the step it starts at, and
|
|
61
|
-
only a graph has named nodes; `entrypoint`/`task` identifies a task by its positional call ordinal,
|
|
62
|
-
which renumbers on any edit to the function — under a file watcher that is the common case, not the
|
|
63
|
-
corner case. The functional API stays exactly where it is, inside `makeAgentModel`'s ReAct loop.
|
|
64
|
-
|
|
65
|
-
**Edges are `after: string[]`.** Several steps naming one predecessor fan out; one step naming
|
|
66
|
-
several joins them, and the join waits for ALL of them (the array form of `addEdge`, which is a
|
|
67
|
-
barrier — separate single edges would fire on the first). Branching is `skipWhen`, never a
|
|
68
|
-
conditional edge: a branch expressed as an edge is invisible to a resume, while a branch expressed
|
|
69
|
-
as a guard is the same mechanism that makes a resume correct.
|
|
70
|
-
|
|
71
|
-
**The graph is compiled per run and the steps close over their dependencies.** Passing collaborators
|
|
72
|
-
through the engine's config would make a run depend on which config keys a given LangGraph minor
|
|
73
|
-
propagates into a node body. A closure cannot be lost.
|
|
74
|
-
|
|
75
|
-
## Pipeline plugins
|
|
76
|
-
|
|
77
|
-
```ts
|
|
78
|
-
interface PipelinePlugin<S, C> {
|
|
79
|
-
alias: string; order?: number // seated by alias, run by ascending order
|
|
80
|
-
enter?: (event) => void // once per invoke/resume: mode fresh|continue|restart, inherited steps, parent
|
|
81
|
-
beforeStep?: (event) => { results?: StepResults } | void // the step WILL run; may hand it ctx.results
|
|
82
|
-
afterStep?: (event) => void // patch merged into state, BEFORE the row commit marks the step done
|
|
83
|
-
passStep?: (event) => void // reason: 'skipped' (guard) | 'failed' (optional step, run goes on)
|
|
84
|
-
exit?: (event) => void // once, with the result the caller is about to receive
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
**A plugin watches a run; it never writes the state and never decides where the run stands.**
|
|
89
|
-
Whatever it keeps, it keeps in a store of its own. `afterStep` runs before the commit so a plugin's
|
|
90
|
-
own write lands before the step is durably done — a crash between the two re-runs the step rather
|
|
91
|
-
than leaving a done step with nothing recorded about it.
|
|
92
|
-
|
|
93
|
-
**A plugin that throws costs a warning, never the run** — unless `options.fatal` calls the error
|
|
94
|
-
fatal: then it takes the exact path a fatal step error takes, the row written `Failed` first and the
|
|
95
|
-
error rethrown (from `enter`, `passStep` and `exit` too). The runner's stop signal passes through.
|
|
96
|
-
|
|
97
|
-
**Seating nothing changes nothing.** Every hook site is guarded, so a pipeline without plugins awaits
|
|
98
|
-
nothing it did not await before — its parallel steps interleave identically and its step context
|
|
99
|
-
has no `results` key. `tests/pipeline-compat.spec.ts` pins this with golden rows, trace lines and
|
|
100
|
-
progress events recorded from the runner before the seam existed; it must stay green unedited.
|
|
101
|
-
|
|
102
|
-
`asStep` passes the composing step to the child as `PipelineInvokeArgs.parent` (read-only:
|
|
103
|
-
pipeline, run id, step, and the parent step's `results`); the child's plugins see it on `enter`.
|
|
104
|
-
|
|
105
|
-
## Cumulative pipeline results
|
|
106
|
-
|
|
107
|
-
After each step, code reads what the step produced into FACTS (`CumulativeResultFact`: a type's
|
|
108
|
-
shape and import specifier, an endpoint's method/path/guard, a resource's table, a file) and every
|
|
109
|
-
later step is told them — so it uses the authoritative names instead of re-deriving them.
|
|
110
|
-
|
|
111
|
-
```ts
|
|
112
|
-
const pipeline = makePipeline<State, Deps>(spec, {
|
|
113
|
-
steps, runs,
|
|
114
|
-
plugins: [cumulativeResultsPlugin<State, Deps>({
|
|
115
|
-
spec: { steps: { types: { extractors: ['ts-types'], full: ['endpoints'] } } }, // or run => spec | null
|
|
116
|
-
extractors: { 'ts-types': { scope: ({ deps }) => deps.glob('src/types/**'), extract: readTypes } },
|
|
117
|
-
store, // CumulativeResultStore; share it with composed pipelines
|
|
118
|
-
})],
|
|
119
|
-
})
|
|
120
|
-
// inside a step:
|
|
121
|
-
const exec = executions().withResults(taskExec, ctx.results?.view) // every model built from it composes the view
|
|
122
|
-
ctx.results?.record({ files: written }) // what the step touched
|
|
123
|
-
ctx.results?.facts({ kind: 'type', name: 'User' }) // typed query for code
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
- **Extractors are deterministic code, never a model call.** A rebuild after a crash must find
|
|
127
|
-
exactly what the first pass found. `scope` recomputes the files an extractor answers for from
|
|
128
|
-
DURABLE inputs (state keys, the file tree), never from what a step reported — it is what a rebuild
|
|
129
|
-
reads. Declarations name extractors; the plugin holds the code.
|
|
130
|
-
- **The ledger is an optimization, never the authority.** A fresh start or restart clears the run's
|
|
131
|
-
own entries (and those of runs composed under it); a continuation loads them and silently
|
|
132
|
-
REBUILDS any missing entry of a finished step from its durable scope. Resume correctness never
|
|
133
|
-
depends on the store; a failing store is a warning. A step's `record({ facts })`-only facts with
|
|
134
|
-
no extractor cannot be rebuilt.
|
|
135
|
-
- **A view is cut once per step**: predecessors only (siblings may not have run), full within
|
|
136
|
-
`window` edges (default 2) or when the producer names the step in `full` (`'*'` for every step),
|
|
137
|
-
names only beyond, never shown when named in `omit`. Over `maxChars` the OLDEST entries not naming
|
|
138
|
-
the step go to names only, then out (listed in `view.omitted`); named ones last; an entry's own
|
|
139
|
-
text is never cut. `facts()` answers from every visible entry regardless of the prompt budget.
|
|
140
|
-
- **A fact belongs to the first entry that produced it** — the step's predecessors and the runs
|
|
141
|
-
composed under the step itself. A later re-extraction never duplicates it.
|
|
142
|
-
- **A later step that rewrites an earlier entry's files refreshes it**: re-extracted from its own
|
|
143
|
-
sources, revision bumped, facts about untouched files kept (`refresh: false` opts out). Entries of
|
|
144
|
-
other pipelines are never refreshed — their extractors live elsewhere.
|
|
145
|
-
- **A skipped step** keeps a stored entry, or gets one rebuilt from its files; **a failed optional
|
|
146
|
-
step** gets a `partial` entry from what it left behind.
|
|
147
|
-
- **Model summaries are OFF unless a step declares `summary`** and the plugin has `summarize`.
|
|
148
|
-
The request carries a ready prompt and schema; the answer is rendered deterministically, capped
|
|
149
|
-
in code, always labelled "not verified", and a failure is a warning without the summary.
|
|
150
|
-
- **A composed run shares its parent's ledger** (parent's, else the root run id); its steps see the
|
|
151
|
-
parent's view for the composing step, and the parent's later steps see the child's entries,
|
|
152
|
-
labelled `<composingStep>/<childStep>` and ordered inside the composing step. Both pipelines must
|
|
153
|
-
be given the SAME store.
|
|
154
|
-
- **Seeds** are facts known before any step ran, visible to every step. A declaration resolved to
|
|
155
|
-
`null`/`false` leaves that run without `ctx.results` at all.
|
|
156
|
-
|
|
157
39
|
## The agent plugin seam
|
|
158
40
|
|
|
159
41
|
```ts
|
|
@@ -173,10 +55,27 @@ itself does not know those features exist.
|
|
|
173
55
|
|
|
174
56
|
## Rules
|
|
175
57
|
|
|
176
|
-
**Contributed context goes to `PromptBlock.Context` and nowhere else.**
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
that every
|
|
58
|
+
**Contributed context goes to `PromptBlock.Context` and nowhere else.** `AgentOptions.context`,
|
|
59
|
+
`invoke`'s `args.context` and every plugin's `context()` land there — in the project message, the
|
|
60
|
+
user turn right after the system — below the system's cached `Role` + `Skills` and `Packages`
|
|
61
|
+
prefix that every run of a persona shares. The project message is stable for one run and is cached
|
|
62
|
+
for its rounds; volatile material anywhere above it would cost every run sharing the persona a
|
|
63
|
+
cache write.
|
|
64
|
+
|
|
65
|
+
**The loop's prompt is composed once and marked per round.** The run sends
|
|
66
|
+
`[system, project message, opening, …rounds]`: the system as real text in a `SystemMessage` (never a
|
|
67
|
+
`JSON.stringify`d block array), and the composed Tail on a COPY of the opening, so the transcript
|
|
68
|
+
keeps the caller's message. Each round hands the wire to the provider plugin's
|
|
69
|
+
`loopCache(wire, agentModel, hints)` — it strips and re-marks copies, the opening at its boundaries
|
|
70
|
+
and the growing conversation read back round after round — and streams with the call options it
|
|
71
|
+
returns. The plugin is `AgentOptions.provider ?? llmPluginRegistry.resolveFor(agentModel)`, resolved
|
|
72
|
+
on the unbound model. `cacheSystem: false` on the persona sends no markers. Detail:
|
|
73
|
+
[[llm-prompt-caching]].
|
|
74
|
+
|
|
75
|
+
**`spectate` gets the turn and the answering model.** `AgentSpectateHook(input, message, action,
|
|
76
|
+
retries, startedAt?, model?)` is called once per round with the turn number as `retries` and the
|
|
77
|
+
agent model's id as `model`, after `cacheHelper.withCacheTiers` has carried a 1-hour cache write
|
|
78
|
+
into the usage.
|
|
180
79
|
|
|
181
80
|
**A run that exceeds `maxTurns` throws `AgentLoopExhaustedError`.** The ceiling counts tool rounds
|
|
182
81
|
(`DEFAULT_MAX_TURNS` is 64, `AgentOptions.maxTurns` overrides it), and it is reached only when the
|
|
@@ -237,41 +136,6 @@ forgetting, which is not a decision one caller has the standing to take. A node
|
|
|
237
136
|
the context window on knowledge the run cannot tell apart from what it needs; the agent pulls what it
|
|
238
137
|
wants by name.
|
|
239
138
|
|
|
240
|
-
**The run ROW is the authority on where a run stands — never the LangGraph checkpoint.** The
|
|
241
|
-
checkpoint is size-guarded and expires, so a design that reads a run's position out of it has a
|
|
242
|
-
silent hole exactly where a crashed run needs an answer. Every reader of a position — a resume, a
|
|
243
|
-
reconciler, an operator, a status endpoint — reads the row. With no checkpointer bound at all, a
|
|
244
|
-
resume is still correct; the checkpointer buys replay, never correctness.
|
|
245
|
-
|
|
246
|
-
**Every step is guarded twice.** The runner refuses to re-enter a step its row calls complete, and
|
|
247
|
-
the application's `skipWhen` reads a durable marker the step itself wrote. The first covers a clean
|
|
248
|
-
crash; the second covers a crash BETWEEN the side effect and the row write, which the first cannot
|
|
249
|
-
see. A step that does N undoable things in a loop marks a cursor with `ctx.mark`.
|
|
250
|
-
|
|
251
|
-
**A pipeline state is scalars and KEYS.** Ids, revisions, markers, lists of codes — never an
|
|
252
|
-
artifact. The state is serialized into the row at every step boundary, so a field carrying a
|
|
253
|
-
document writes one copy of it per step. Over `maxStateChars` the step FAILS: refused, never
|
|
254
|
-
truncated, because a resume replaying from a cut-down state replays from a state that never existed.
|
|
255
|
-
|
|
256
|
-
**A step failure is an OUTCOME, not a throw.** `invoke`/`resume` return
|
|
257
|
-
`{ status: Failed, failedAt, error }`, because every caller has a status, a warning or a record to
|
|
258
|
-
write before it decides anything, and a throwing runner puts that in a `catch` where it gets
|
|
259
|
-
forgotten. The one exception is `options.fatal`: those are written to the row Failed FIRST and then
|
|
260
|
-
rethrown, so an exhausted budget cannot become a result a caller carries on from.
|
|
261
|
-
|
|
262
|
-
**No default retry.** `attempts` defaults to 1, because retry budgets in this family MULTIPLY — an
|
|
263
|
-
outer retry around a model's own inner retry is their product. `attempts > 1` on a `nonIdempotent`
|
|
264
|
-
step is refused at build time: an automatic retry is exactly what that flag says must not happen.
|
|
265
|
-
|
|
266
|
-
**`nonIdempotent` marks a step whose side effect cannot be undone** — a wipe, a purge, a claim
|
|
267
|
-
against a rate-limited authority, a model call whose output is already on disk. `resume({ from })`
|
|
268
|
-
refuses to re-enter a completed one without `force`.
|
|
269
|
-
|
|
270
|
-
**A ReAct run is not a resumable unit, and that is why `makeAgentModel` still builds its
|
|
271
|
-
`entrypoint` inside `invoke()`.** Its state is an unbounded message list whose tool results are side
|
|
272
|
-
effects already applied to the world: re-entering a turn re-applies them. What IS resumable is a
|
|
273
|
-
pipeline — and an agent run belongs inside one of its steps.
|
|
274
|
-
|
|
275
139
|
**`toolHelper.safeInvokeTool(tools, call, fatal?)` takes a fatal predicate.** Containment is right for a bad
|
|
276
140
|
argument and wrong for an exhausted budget: a tool may be a whole pipeline behind one call, and
|
|
277
141
|
handing the model a readable "out of tokens" is an invitation to pick another tool and spend again.
|
|
@@ -280,19 +144,18 @@ handing the model a readable "out of tokens" is an invitation to pick another to
|
|
|
280
144
|
name first and only re-reads it as a serialized token once the provider throws — returning null
|
|
281
145
|
would break every restore.
|
|
282
146
|
|
|
283
|
-
## Testing
|
|
284
|
-
|
|
285
|
-
Category A (unit, no env, no network). The model is doubled with a small scripted object in
|
|
286
|
-
`tests/_tools/model.ts` because `@langchain/core`'s own `FakeStreamingChatModel` always replays its
|
|
287
|
-
first response and so cannot drive a tool loop. That double stands in for the MODEL, an external
|
|
288
|
-
boundary — never for an `@owlmeans/*` package. The cumulative-results specs keep the project as a
|
|
289
|
-
`Map` of files in `deps` — the durable input extractors read — so a "new process" is a new plugin
|
|
290
|
-
over the same files.
|
|
291
|
-
|
|
292
147
|
## Related
|
|
293
148
|
|
|
294
149
|
- [[agent-common]] — the serializable records and the run lifecycle flow
|
|
295
150
|
- [[llm]] — `Execution`, the model contract and the `advise`-only `ExecutionPlugin`
|
|
296
151
|
- [[agent-checkpoint]] — the durable Mongo implementation of both storage ports (internal)
|
|
297
152
|
- [[llm-prompt-caching]] — which block contributed context lands in, and why
|
|
298
|
-
- [[agent-skills]] — `
|
|
153
|
+
- [[agent-skills]] — `owlmeansPackagesPlugin`, the prompt plugin that loads package skills on agent runs too
|
|
154
|
+
|
|
155
|
+
## Parts
|
|
156
|
+
|
|
157
|
+
| Part | Load it when |
|
|
158
|
+
|---|---|
|
|
159
|
+
| [pipelines](parts/pipelines.md) | declaring or running a pipeline, writing a pipeline plugin, or resuming a run |
|
|
160
|
+
| [cumulative-results](parts/cumulative-results.md) | telling a pipeline's later steps what earlier steps produced, or writing an extractor |
|
|
161
|
+
| [testing](parts/testing.md) | writing tests that drive an agent loop or a pipeline |
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cumulative-results
|
|
3
|
+
description: Cumulative pipeline results — deterministic extractors, the ledger and its rebuild, how a step's view is cut, refresh, model summaries, composed runs and seeds.
|
|
4
|
+
metadata:
|
|
5
|
+
purposes: agent, job
|
|
6
|
+
mentions: cumulativeResultsPlugin, CUMULATIVE_RESULTS_PLUGIN, CumulativeResultStore, CumulativeResultFact, DEFAULT_RESULT_SUMMARY_SCHEMA, ctx.results, withResults
|
|
7
|
+
---
|
|
8
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
9
|
+
|
|
10
|
+
# @owlmeans/agent — Cumulative pipeline results
|
|
11
|
+
|
|
12
|
+
## Cumulative pipeline results
|
|
13
|
+
|
|
14
|
+
After each step, code reads what the step produced into FACTS (`CumulativeResultFact`: a type's
|
|
15
|
+
shape and import specifier, an endpoint's method/path/guard, a resource's table, a file) and every
|
|
16
|
+
later step is told them — so it uses the authoritative names instead of re-deriving them.
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
const pipeline = makePipeline<State, Deps>(spec, {
|
|
20
|
+
steps, runs,
|
|
21
|
+
plugins: [cumulativeResultsPlugin<State, Deps>({
|
|
22
|
+
spec: { steps: { types: { extractors: ['ts-types'], full: ['endpoints'] } } }, // or run => spec | null
|
|
23
|
+
extractors: { 'ts-types': { scope: ({ deps }) => deps.glob('src/types/**'), extract: readTypes } },
|
|
24
|
+
store, // CumulativeResultStore; share it with composed pipelines
|
|
25
|
+
})],
|
|
26
|
+
})
|
|
27
|
+
// inside a step:
|
|
28
|
+
const exec = executions().withResults(taskExec, ctx.results?.view) // every model built from it composes the view
|
|
29
|
+
ctx.results?.record({ files: written }) // what the step touched
|
|
30
|
+
ctx.results?.facts({ kind: 'type', name: 'User' }) // typed query for code
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- **Extractors are deterministic code, never a model call.** A rebuild after a crash must find
|
|
34
|
+
exactly what the first pass found. `scope` recomputes the files an extractor answers for from
|
|
35
|
+
DURABLE inputs (state keys, the file tree), never from what a step reported — it is what a rebuild
|
|
36
|
+
reads. Declarations name extractors; the plugin holds the code.
|
|
37
|
+
- **The ledger is an optimization, never the authority.** A fresh start or restart clears the run's
|
|
38
|
+
own entries (and those of runs composed under it); a continuation loads them and silently
|
|
39
|
+
REBUILDS any missing entry of a finished step from its durable scope. Resume correctness never
|
|
40
|
+
depends on the store; a failing store is a warning. A step's `record({ facts })`-only facts with
|
|
41
|
+
no extractor cannot be rebuilt.
|
|
42
|
+
- **A view is cut once per step**: predecessors only (siblings may not have run), full within
|
|
43
|
+
`window` edges (default 2) or when the producer names the step in `full` (`'*'` for every step),
|
|
44
|
+
names only beyond, never shown when named in `omit`. Over `maxChars` the OLDEST entries not naming
|
|
45
|
+
the step go to names only, then out (listed in `view.omitted`); named ones last; an entry's own
|
|
46
|
+
text is never cut. `facts()` answers from every visible entry regardless of the prompt budget.
|
|
47
|
+
- **A fact belongs to the first entry that produced it** — the step's predecessors and the runs
|
|
48
|
+
composed under the step itself. A later re-extraction never duplicates it.
|
|
49
|
+
- **A later step that rewrites an earlier entry's files refreshes it**: re-extracted from its own
|
|
50
|
+
sources, revision bumped, facts about untouched files kept (`refresh: false` opts out). Entries of
|
|
51
|
+
other pipelines are never refreshed — their extractors live elsewhere.
|
|
52
|
+
- **A skipped step** keeps a stored entry, or gets one rebuilt from its files; **a failed optional
|
|
53
|
+
step** gets a `partial` entry from what it left behind.
|
|
54
|
+
- **Model summaries are OFF unless a step declares `summary`** and the plugin has `summarize`.
|
|
55
|
+
The request carries a ready prompt and schema; the answer is rendered deterministically, capped
|
|
56
|
+
in code, always labelled "not verified", and a failure is a warning without the summary.
|
|
57
|
+
- **A composed run shares its parent's ledger** (parent's, else the root run id); its steps see the
|
|
58
|
+
parent's view for the composing step, and the parent's later steps see the child's entries,
|
|
59
|
+
labelled `<composingStep>/<childStep>` and ordered inside the composing step. Both pipelines must
|
|
60
|
+
be given the SAME store.
|
|
61
|
+
- **Seeds** are facts known before any step ran, visible to every step. A declaration resolved to
|
|
62
|
+
`null`/`false` leaves that run without `ctx.results` at all.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pipelines
|
|
3
|
+
description: Resumable pipelines over a checkpointed StateGraph — steps and edges, the PipelinePlugin seam, and the rules for run rows, step guards, state size, failures and retries.
|
|
4
|
+
metadata:
|
|
5
|
+
purposes: agent, job, state
|
|
6
|
+
mentions: makePipeline, PipelineSpec, PipelinePlugin, asStep, skipWhen, nonIdempotent, makeCheckpointSaver, PipelineRunStore, CheckpointStore, maxStateChars, ctx.mark, @owlmeans/agent/pipeline
|
|
7
|
+
---
|
|
8
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
9
|
+
|
|
10
|
+
# @owlmeans/agent — Pipelines
|
|
11
|
+
|
|
12
|
+
## Pipelines
|
|
13
|
+
|
|
14
|
+
A pipeline is a **state machine over named steps** whose position is persisted at every step
|
|
15
|
+
boundary, so a run killed anywhere continues from the step it stopped at rather than from zero.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const spec: PipelineSpec = {
|
|
19
|
+
alias: 'vib:story:design', version: 1,
|
|
20
|
+
steps: [
|
|
21
|
+
{ step: 'screens' },
|
|
22
|
+
{ step: 'ux', after: ['screens'] },
|
|
23
|
+
{ step: 'data', after: ['screens'] }, // runs BESIDE `ux`
|
|
24
|
+
{ step: 'persist', after: ['ux', 'data'] }, // joins BOTH
|
|
25
|
+
],
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const pipeline = makePipeline<State, Deps>(spec, { steps, runs, checkpointer, fatal })
|
|
29
|
+
await pipeline.invoke(seed, { runId, deps, scope: projectId })
|
|
30
|
+
await pipeline.resume(runId, { deps, from: 'data' })
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**`StateGraph`, not the functional API.** A resume must be able to name the step it starts at, and
|
|
34
|
+
only a graph has named nodes; `entrypoint`/`task` identifies a task by its positional call ordinal,
|
|
35
|
+
which renumbers on any edit to the function — under a file watcher that is the common case, not the
|
|
36
|
+
corner case. The functional API stays exactly where it is, inside `makeAgentModel`'s ReAct loop.
|
|
37
|
+
|
|
38
|
+
**Edges are `after: string[]`.** Several steps naming one predecessor fan out; one step naming
|
|
39
|
+
several joins them, and the join waits for ALL of them (the array form of `addEdge`, which is a
|
|
40
|
+
barrier — separate single edges would fire on the first). Branching is `skipWhen`, never a
|
|
41
|
+
conditional edge: a branch expressed as an edge is invisible to a resume, while a branch expressed
|
|
42
|
+
as a guard is the same mechanism that makes a resume correct.
|
|
43
|
+
|
|
44
|
+
**The graph is compiled per run and the steps close over their dependencies.** Passing collaborators
|
|
45
|
+
through the engine's config would make a run depend on which config keys a given LangGraph minor
|
|
46
|
+
propagates into a node body. A closure cannot be lost.
|
|
47
|
+
|
|
48
|
+
## Pipeline plugins
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
interface PipelinePlugin<S, C> {
|
|
52
|
+
alias: string; order?: number // seated by alias, run by ascending order
|
|
53
|
+
enter?: (event) => void // once per invoke/resume: mode fresh|continue|restart, inherited steps, parent
|
|
54
|
+
beforeStep?: (event) => { results?: StepResults } | void // the step WILL run; may hand it ctx.results
|
|
55
|
+
afterStep?: (event) => void // patch merged into state, BEFORE the row commit marks the step done
|
|
56
|
+
passStep?: (event) => void // reason: 'skipped' (guard) | 'failed' (optional step, run goes on)
|
|
57
|
+
exit?: (event) => void // once, with the result the caller is about to receive
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**A plugin watches a run; it never writes the state and never decides where the run stands.**
|
|
62
|
+
Whatever it keeps, it keeps in a store of its own. `afterStep` runs before the commit so a plugin's
|
|
63
|
+
own write lands before the step is durably done — a crash between the two re-runs the step rather
|
|
64
|
+
than leaving a done step with nothing recorded about it.
|
|
65
|
+
|
|
66
|
+
**A plugin that throws costs a warning, never the run** — unless `options.fatal` calls the error
|
|
67
|
+
fatal: then it takes the exact path a fatal step error takes, the row written `Failed` first and the
|
|
68
|
+
error rethrown (from `enter`, `passStep` and `exit` too). The runner's stop signal passes through.
|
|
69
|
+
|
|
70
|
+
**Seating nothing changes nothing.** Every hook site is guarded, so a pipeline without plugins awaits
|
|
71
|
+
nothing it did not await before — its parallel steps interleave identically and its step context
|
|
72
|
+
has no `results` key. `tests/pipeline-compat.spec.ts` pins this with golden rows, trace lines and
|
|
73
|
+
progress events recorded from the runner before the seam existed; it must stay green unedited.
|
|
74
|
+
|
|
75
|
+
`asStep` passes the composing step to the child as `PipelineInvokeArgs.parent` (read-only:
|
|
76
|
+
pipeline, run id, step, and the parent step's `results`); the child's plugins see it on `enter`.
|
|
77
|
+
|
|
78
|
+
## Rules
|
|
79
|
+
|
|
80
|
+
**The run ROW is the authority on where a run stands — never the LangGraph checkpoint.** The
|
|
81
|
+
checkpoint is size-guarded and expires, so a design that reads a run's position out of it has a
|
|
82
|
+
silent hole exactly where a crashed run needs an answer. Every reader of a position — a resume, a
|
|
83
|
+
reconciler, an operator, a status endpoint — reads the row. With no checkpointer bound at all, a
|
|
84
|
+
resume is still correct; the checkpointer buys replay, never correctness.
|
|
85
|
+
|
|
86
|
+
**Every step is guarded twice.** The runner refuses to re-enter a step its row calls complete, and
|
|
87
|
+
the application's `skipWhen` reads a durable marker the step itself wrote. The first covers a clean
|
|
88
|
+
crash; the second covers a crash BETWEEN the side effect and the row write, which the first cannot
|
|
89
|
+
see. A step that does N undoable things in a loop marks a cursor with `ctx.mark`.
|
|
90
|
+
|
|
91
|
+
**A pipeline state is scalars and KEYS.** Ids, revisions, markers, lists of codes — never an
|
|
92
|
+
artifact. The state is serialized into the row at every step boundary, so a field carrying a
|
|
93
|
+
document writes one copy of it per step. Over `maxStateChars` the step FAILS: refused, never
|
|
94
|
+
truncated, because a resume replaying from a cut-down state replays from a state that never existed.
|
|
95
|
+
|
|
96
|
+
**A step failure is an OUTCOME, not a throw.** `invoke`/`resume` return
|
|
97
|
+
`{ status: Failed, failedAt, error }`, because every caller has a status, a warning or a record to
|
|
98
|
+
write before it decides anything, and a throwing runner puts that in a `catch` where it gets
|
|
99
|
+
forgotten. The one exception is `options.fatal`: those are written to the row Failed FIRST and then
|
|
100
|
+
rethrown, so an exhausted budget cannot become a result a caller carries on from.
|
|
101
|
+
|
|
102
|
+
**No default retry.** `attempts` defaults to 1, because retry budgets in this family MULTIPLY — an
|
|
103
|
+
outer retry around a model's own inner retry is their product. `attempts > 1` on a `nonIdempotent`
|
|
104
|
+
step is refused at build time: an automatic retry is exactly what that flag says must not happen.
|
|
105
|
+
|
|
106
|
+
**`nonIdempotent` marks a step whose side effect cannot be undone** — a wipe, a purge, a claim
|
|
107
|
+
against a rate-limited authority, a model call whose output is already on disk. `resume({ from })`
|
|
108
|
+
refuses to re-enter a completed one without `force`.
|
|
109
|
+
|
|
110
|
+
**A ReAct run is not a resumable unit, and that is why `makeAgentModel` still builds its
|
|
111
|
+
`entrypoint` inside `invoke()`.** Its state is an unbounded message list whose tool results are side
|
|
112
|
+
effects already applied to the world: re-entering a turn re-applies them. What IS resumable is a
|
|
113
|
+
pipeline — and an agent run belongs inside one of its steps.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing
|
|
3
|
+
description: Unit tests of agents and pipelines with a scripted model double and files kept in deps.
|
|
4
|
+
metadata:
|
|
5
|
+
purposes: test
|
|
6
|
+
mentions: FakeStreamingChatModel
|
|
7
|
+
---
|
|
8
|
+
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
9
|
+
|
|
10
|
+
# @owlmeans/agent — Testing
|
|
11
|
+
|
|
12
|
+
## Testing
|
|
13
|
+
|
|
14
|
+
Category A (unit, no env, no network). The model is doubled with a small scripted object in
|
|
15
|
+
`tests/_tools/model.ts` because `@langchain/core`'s own `FakeStreamingChatModel` always replays its
|
|
16
|
+
first response and so cannot drive a tool loop. That double stands in for the MODEL, an external
|
|
17
|
+
boundary — never for an `@owlmeans/*` package. The cumulative-results specs keep the project as a
|
|
18
|
+
`Map` of files in `deps` — the durable input extractors read — so a "new process" is a new plugin
|
|
19
|
+
over the same files.
|
package/build/model.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EACV,UAAU,EAAE,YAAY,EACzB,MAAM,YAAY,CAAA;AA6BnB;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,cAAc,YAAa,YAAY,KAAG,UAmRtD,CAAA"}
|
package/build/model.js
CHANGED
|
@@ -2,13 +2,35 @@ import { AIMessage, HumanMessage, SystemMessage, ToolMessage } from '@langchain/
|
|
|
2
2
|
import { addMessages, entrypoint, task } from '@langchain/langgraph';
|
|
3
3
|
import { createIdOfLength } from '@owlmeans/basic-ids';
|
|
4
4
|
import { makeFlowModel } from '@owlmeans/flow';
|
|
5
|
-
import {
|
|
5
|
+
import { PromptRegion } from '@owlmeans/llm-common';
|
|
6
|
+
import { cacheHelper, llmPluginRegistry } from '@owlmeans/llm';
|
|
6
7
|
import { logger } from '@owlmeans/log';
|
|
7
8
|
import { AgentRunStatus, AgentRunTransition, agentRunFlow, conversationFor, } from '@owlmeans/agent-common';
|
|
8
9
|
import { DEFAULT_ACTION, DEFAULT_ENTRYPOINT, DEFAULT_MAX_TURNS, DEFAULT_PLUGIN_ORDER } from './consts.js';
|
|
9
10
|
import { AgentLoopExhaustedError, AgentMissconfiguredError } from './errors.js';
|
|
10
11
|
import { toolHelper } from './helpers/tools.js';
|
|
11
12
|
const log = logger('agent');
|
|
13
|
+
/**
|
|
14
|
+
* A copy of the opening with the per-call tail after its payload — a string stays a string. The
|
|
15
|
+
* opening itself stays in the transcript untouched; only the wire carries the tail.
|
|
16
|
+
*/
|
|
17
|
+
const withTail = (opening, tail) => {
|
|
18
|
+
if (opening.getType() !== 'human') {
|
|
19
|
+
return [opening, new HumanMessage({ content: tail })];
|
|
20
|
+
}
|
|
21
|
+
const content = typeof opening.content === 'string'
|
|
22
|
+
? `${opening.content}\n\n${tail}`
|
|
23
|
+
: [...opening.content, { type: 'text', text: tail }];
|
|
24
|
+
return [new HumanMessage({
|
|
25
|
+
content, id: opening.id, name: opening.name, additional_kwargs: opening.additional_kwargs,
|
|
26
|
+
})];
|
|
27
|
+
};
|
|
28
|
+
/** The provider's id of the model a run talks to, for billing — the config's, else the client's own. */
|
|
29
|
+
const modelIdOf = (model) => {
|
|
30
|
+
const typed = model;
|
|
31
|
+
const id = typed.metadata?.config?.model ?? typed.model ?? typed.modelName;
|
|
32
|
+
return typeof id === 'string' ? id : undefined;
|
|
33
|
+
};
|
|
12
34
|
/**
|
|
13
35
|
* An OwlMeans agent over the LangGraph functional API.
|
|
14
36
|
*
|
|
@@ -34,7 +56,8 @@ export const makeAgentModel = (options) => {
|
|
|
34
56
|
}
|
|
35
57
|
const conversation = options.conversation ?? conversationFor(exec.purpose);
|
|
36
58
|
const prompts = options.prompts ?? exec.prompts;
|
|
37
|
-
const provider = options.provider ?? llmPluginRegistry.
|
|
59
|
+
const provider = options.provider ?? llmPluginRegistry.resolveFor(agentModel);
|
|
60
|
+
const modelId = modelIdOf(agentModel);
|
|
38
61
|
const purpose = exec.purpose;
|
|
39
62
|
const registry = [];
|
|
40
63
|
const ordered = () => [...registry].sort((a, b) => (a.order ?? DEFAULT_PLUGIN_ORDER) - (b.order ?? DEFAULT_PLUGIN_ORDER));
|
|
@@ -107,26 +130,45 @@ export const makeAgentModel = (options) => {
|
|
|
107
130
|
results: exec.results,
|
|
108
131
|
})
|
|
109
132
|
: null;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
133
|
+
// The opening of every round: the system (a persona, stable across runs), the project
|
|
134
|
+
// message (this run's facts), and the caller's opening carrying the per-call tail. The system
|
|
135
|
+
// goes out as real text — its cache blocks are the provider plugin's, never a stringified array.
|
|
136
|
+
const system = composed != null ? composed.system ?? '' : context.join('\n\n');
|
|
137
|
+
const head = [
|
|
138
|
+
...(system !== '' ? [new SystemMessage(system)] : []),
|
|
139
|
+
...(composed?.project != null ? [new HumanMessage(composed.project)] : []),
|
|
140
|
+
];
|
|
141
|
+
const hints = {
|
|
142
|
+
system: composed?.blocks.filter(block => block.region === PromptRegion.System),
|
|
143
|
+
...(composed?.project != null ? { project: head.length - 1 } : {}),
|
|
144
|
+
...(composed != null ? { ttl: composed.cache.ttl } : {}),
|
|
145
|
+
};
|
|
146
|
+
const cached = composed?.cache.enabled !== false;
|
|
113
147
|
const tooled = agentModel.bindTools?.(Object.values(toolSet)) ?? agentModel;
|
|
114
|
-
const ask = task('call-llm', async (messages) => {
|
|
148
|
+
const ask = task('call-llm', async ({ messages, turn }) => {
|
|
115
149
|
const startedAt = Date.now();
|
|
116
|
-
const
|
|
150
|
+
const [first, ...rest] = messages;
|
|
151
|
+
const opening = composed?.tail != null && first != null ? withTail(first, composed.tail) : [first];
|
|
152
|
+
const wire = [...head, ...opening, ...rest].filter(message => message != null);
|
|
153
|
+
// Each round strips and re-marks copies: the system and project message once, and the
|
|
154
|
+
// growing conversation read back from the round before.
|
|
155
|
+
const patch = cached
|
|
156
|
+
? provider?.loopCache?.(wire, agentModel, hints)
|
|
157
|
+
: undefined;
|
|
158
|
+
const stream = await tooled.stream((patch?.messages ?? wire), { ...patch?.options, runName: action, metadata: { purpose } });
|
|
117
159
|
let final;
|
|
118
160
|
for await (const chunk of stream) {
|
|
119
161
|
final = final != null ? final.concat(chunk) : chunk;
|
|
120
162
|
}
|
|
121
|
-
const result = new AIMessage(final);
|
|
122
|
-
await spectate?.(messages, result, action,
|
|
163
|
+
const result = new AIMessage(cacheHelper.withCacheTiers(final));
|
|
164
|
+
await spectate?.(messages, result, action, turn, startedAt, modelId);
|
|
123
165
|
return result;
|
|
124
166
|
});
|
|
125
167
|
// A rejected task aborts the whole superstep, killing every sibling call in the same batch —
|
|
126
168
|
// `safeInvokeTool` is what keeps a bad argument from costing the work the others finished.
|
|
127
169
|
const call = task('call-tool', async (toolCall) => toolHelper.safeInvokeTool(toolSet, toolCall, options.fatal));
|
|
128
170
|
const agent = entrypoint(entrypointName, async (messages) => {
|
|
129
|
-
let response = await ask(messages);
|
|
171
|
+
let response = await ask({ messages, turn: 0 });
|
|
130
172
|
let turn = 0;
|
|
131
173
|
while (true) {
|
|
132
174
|
messages = addMessages(messages, [response]);
|
|
@@ -163,7 +205,7 @@ export const makeAgentModel = (options) => {
|
|
|
163
205
|
});
|
|
164
206
|
}));
|
|
165
207
|
messages = addMessages(messages, results);
|
|
166
|
-
response = await ask(messages);
|
|
208
|
+
response = await ask({ messages, turn });
|
|
167
209
|
}
|
|
168
210
|
return messages;
|
|
169
211
|
});
|
package/build/model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ import type { SummarizeOptions } from './types.js';
|
|
|
10
10
|
*
|
|
11
11
|
* What it contributes is rendered as clearly delimited, explicitly untrusted material. These are
|
|
12
12
|
* model words derived from user input, stored and replayed into a later prompt: they belong in the
|
|
13
|
-
*
|
|
13
|
+
* context block of the project message, described as a record of what happened, never as instructions.
|
|
14
14
|
*/
|
|
15
15
|
export declare const summarizePlugin: (options?: SummarizeOptions) => AgentPlugin;
|
|
16
16
|
//# sourceMappingURL=summarize.d.ts.map
|
|
@@ -12,7 +12,7 @@ import { compactionHelper } from '../helpers/compaction.js';
|
|
|
12
12
|
*
|
|
13
13
|
* What it contributes is rendered as clearly delimited, explicitly untrusted material. These are
|
|
14
14
|
* model words derived from user input, stored and replayed into a later prompt: they belong in the
|
|
15
|
-
*
|
|
15
|
+
* context block of the project message, described as a record of what happened, never as instructions.
|
|
16
16
|
*/
|
|
17
17
|
export const summarizePlugin = (options = {}) => {
|
|
18
18
|
const { store, model, maxSummaryChars = DEFAULT_SUMMARY_CHARS, maxAdviceChars = DEFAULT_ADVICE_CHARS, window = DEFAULT_EVENT_WINDOW, action = 'agent-compaction', onEvent, } = options;
|
package/build/types.d.ts
CHANGED
|
@@ -17,10 +17,11 @@ export interface AgentToolSet {
|
|
|
17
17
|
* What the caller gets told about each model call.
|
|
18
18
|
*
|
|
19
19
|
* Shaped to match `spectate(spectator, callType)` from `@owlmeans/llm` exactly, so an application
|
|
20
|
-
* that already has a spectator passes the curried function straight in.
|
|
20
|
+
* that already has a spectator passes the curried function straight in. `retries` carries the
|
|
21
|
+
* loop's turn number, and `model` the id of the model that answered.
|
|
21
22
|
*/
|
|
22
23
|
export interface AgentSpectateHook {
|
|
23
|
-
(input: ModelInputItem[], message: AIMessage, action: string, retries: number, startedAt?: number): Promise<unknown>;
|
|
24
|
+
(input: ModelInputItem[], message: AIMessage, action: string, retries: number, startedAt?: number, model?: string): Promise<unknown>;
|
|
24
25
|
}
|
|
25
26
|
export interface AgentOptions {
|
|
26
27
|
/** The execution the run belongs to. Its `prompt` policy is the agent's persona. */
|
|
@@ -28,7 +29,10 @@ export interface AgentOptions {
|
|
|
28
29
|
/** Overrides the model resolved from the execution. */
|
|
29
30
|
agentModel?: BaseChatModel;
|
|
30
31
|
tools: AgentToolSet;
|
|
31
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Static context. Lands in `PromptBlock.Context` — the project message, behind the cached
|
|
34
|
+
* system region — never in the system message other runs share.
|
|
35
|
+
*/
|
|
32
36
|
context?: string[];
|
|
33
37
|
conversation?: ConversationRef;
|
|
34
38
|
/** LangGraph entrypoint name; shows up in traces. */
|
|
@@ -41,7 +45,10 @@ export interface AgentOptions {
|
|
|
41
45
|
* by default: the agent holds an execution, not the service that knows its policy.
|
|
42
46
|
*/
|
|
43
47
|
utility?: () => BaseChatModel | undefined;
|
|
44
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Provider plugin used for cache placement. Resolved from the model when omitted
|
|
50
|
+
* (`llmPluginRegistry.resolveFor`, so a model the service built gets its own provider's).
|
|
51
|
+
*/
|
|
45
52
|
provider?: LlmPlugin;
|
|
46
53
|
maxTurns?: number;
|
|
47
54
|
/**
|
|
@@ -65,7 +72,7 @@ export interface AgentOptions {
|
|
|
65
72
|
export interface AgentInvokeArgs {
|
|
66
73
|
/** LangChain `runName` for the model calls of this run. */
|
|
67
74
|
action?: string;
|
|
68
|
-
/** Extra
|
|
75
|
+
/** Extra context for this run only — it joins the project message. */
|
|
69
76
|
context?: string[];
|
|
70
77
|
}
|
|
71
78
|
export interface AgentRunOutcome {
|
package/build/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAA;AAChF,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACpF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AACtF,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACxF,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAA;AAC7H,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAC5E,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAEhF,8FAA8F;AAC9F,MAAM,WAAW,YAAY;IAAG,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,CAAA;CAAE;AAExE
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/agent",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.54",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -68,14 +68,14 @@
|
|
|
68
68
|
"@langchain/langgraph-checkpoint": "^1.1.5"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"@owlmeans/agent-common": "^0.1.18-rc.
|
|
72
|
-
"@owlmeans/basic-ids": "^0.1.18-rc.
|
|
73
|
-
"@owlmeans/context": "^0.1.18-rc.
|
|
74
|
-
"@owlmeans/error": "^0.1.18-rc.
|
|
75
|
-
"@owlmeans/flow": "^0.1.18-rc.
|
|
76
|
-
"@owlmeans/llm": "^0.1.18-rc.
|
|
77
|
-
"@owlmeans/llm-common": "^0.1.18-rc.
|
|
78
|
-
"@owlmeans/log": "^0.1.18-rc.
|
|
71
|
+
"@owlmeans/agent-common": "^0.1.18-rc.50",
|
|
72
|
+
"@owlmeans/basic-ids": "^0.1.18-rc.41",
|
|
73
|
+
"@owlmeans/context": "^0.1.18-rc.35",
|
|
74
|
+
"@owlmeans/error": "^0.1.18-rc.39",
|
|
75
|
+
"@owlmeans/flow": "^0.1.18-rc.46",
|
|
76
|
+
"@owlmeans/llm": "^0.1.18-rc.52",
|
|
77
|
+
"@owlmeans/llm-common": "^0.1.18-rc.40",
|
|
78
|
+
"@owlmeans/log": "^0.1.18-rc.4",
|
|
79
79
|
"ajv": "^8.20.0"
|
|
80
80
|
},
|
|
81
81
|
"publishConfig": {
|
package/src/model.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { AIMessage, HumanMessage, SystemMessage, ToolMessage } from '@langchain/core/messages'
|
|
2
|
-
import type { AIMessageChunk, BaseMessage, BaseMessageLike, ToolCall } from '@langchain/core/messages'
|
|
2
|
+
import type { AIMessageChunk, BaseMessage, BaseMessageLike, MessageFieldWithRole, ToolCall } from '@langchain/core/messages'
|
|
3
3
|
import { addMessages, entrypoint, task } from '@langchain/langgraph'
|
|
4
4
|
import { createIdOfLength } from '@owlmeans/basic-ids'
|
|
5
5
|
import { makeFlowModel } from '@owlmeans/flow'
|
|
6
6
|
import type { FlowModel } from '@owlmeans/flow'
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
7
|
+
import { PromptRegion } from '@owlmeans/llm-common'
|
|
8
|
+
import { cacheHelper, llmPluginRegistry } from '@owlmeans/llm'
|
|
9
|
+
import type { HelperExecution, LlmLoopCacheHints, ModelInputItem } from '@owlmeans/llm'
|
|
9
10
|
import { logger } from '@owlmeans/log'
|
|
10
11
|
import {
|
|
11
12
|
AgentRunStatus, AgentRunTransition, agentRunFlow, conversationFor,
|
|
@@ -19,6 +20,30 @@ import { toolHelper } from './helpers/tools.js'
|
|
|
19
20
|
|
|
20
21
|
const log = logger('agent')
|
|
21
22
|
|
|
23
|
+
/**
|
|
24
|
+
* A copy of the opening with the per-call tail after its payload — a string stays a string. The
|
|
25
|
+
* opening itself stays in the transcript untouched; only the wire carries the tail.
|
|
26
|
+
*/
|
|
27
|
+
const withTail = (opening: BaseMessage, tail: string): BaseMessage[] => {
|
|
28
|
+
if (opening.getType() !== 'human') {
|
|
29
|
+
return [opening, new HumanMessage({ content: tail })]
|
|
30
|
+
}
|
|
31
|
+
const content = typeof opening.content === 'string'
|
|
32
|
+
? `${opening.content}\n\n${tail}`
|
|
33
|
+
: [...opening.content, { type: 'text', text: tail }]
|
|
34
|
+
|
|
35
|
+
return [new HumanMessage({
|
|
36
|
+
content, id: opening.id, name: opening.name, additional_kwargs: opening.additional_kwargs,
|
|
37
|
+
} as ConstructorParameters<typeof HumanMessage>[0])]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** The provider's id of the model a run talks to, for billing — the config's, else the client's own. */
|
|
41
|
+
const modelIdOf = (model: unknown): string | undefined => {
|
|
42
|
+
const typed = model as { metadata?: { config?: { model?: string } }, model?: unknown, modelName?: unknown }
|
|
43
|
+
const id = typed.metadata?.config?.model ?? typed.model ?? typed.modelName
|
|
44
|
+
return typeof id === 'string' ? id : undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
22
47
|
/**
|
|
23
48
|
* An OwlMeans agent over the LangGraph functional API.
|
|
24
49
|
*
|
|
@@ -49,7 +74,8 @@ export const makeAgentModel = (options: AgentOptions): AgentModel => {
|
|
|
49
74
|
|
|
50
75
|
const conversation = options.conversation ?? conversationFor(exec.purpose)
|
|
51
76
|
const prompts = options.prompts ?? exec.prompts
|
|
52
|
-
const provider = options.provider ?? llmPluginRegistry.
|
|
77
|
+
const provider = options.provider ?? llmPluginRegistry.resolveFor(agentModel)
|
|
78
|
+
const modelId = modelIdOf(agentModel)
|
|
53
79
|
const purpose = exec.purpose
|
|
54
80
|
|
|
55
81
|
const registry: AgentPlugin[] = []
|
|
@@ -136,20 +162,38 @@ export const makeAgentModel = (options: AgentOptions): AgentModel => {
|
|
|
136
162
|
},
|
|
137
163
|
)
|
|
138
164
|
: null
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
165
|
+
// The opening of every round: the system (a persona, stable across runs), the project
|
|
166
|
+
// message (this run's facts), and the caller's opening carrying the per-call tail. The system
|
|
167
|
+
// goes out as real text — its cache blocks are the provider plugin's, never a stringified array.
|
|
168
|
+
const system = composed != null ? composed.system ?? '' : context.join('\n\n')
|
|
169
|
+
const head: BaseMessage[] = [
|
|
170
|
+
...(system !== '' ? [new SystemMessage(system)] : []),
|
|
171
|
+
...(composed?.project != null ? [new HumanMessage(composed.project)] : []),
|
|
172
|
+
]
|
|
173
|
+
const hints: LlmLoopCacheHints = {
|
|
174
|
+
system: composed?.blocks.filter(block => block.region === PromptRegion.System),
|
|
175
|
+
...(composed?.project != null ? { project: head.length - 1 } : {}),
|
|
176
|
+
...(composed != null ? { ttl: composed.cache.ttl } : {}),
|
|
177
|
+
}
|
|
178
|
+
const cached = composed?.cache.enabled !== false
|
|
144
179
|
|
|
145
180
|
const tooled = agentModel.bindTools?.(Object.values(toolSet)) ?? agentModel
|
|
146
181
|
|
|
147
|
-
const ask = task('call-llm', async (messages: BaseMessageLike[]) => {
|
|
182
|
+
const ask = task('call-llm', async ({ messages, turn }: { messages: BaseMessageLike[], turn: number }) => {
|
|
148
183
|
const startedAt = Date.now()
|
|
149
184
|
|
|
185
|
+
const [first, ...rest] = messages as BaseMessage[]
|
|
186
|
+
const opening = composed?.tail != null && first != null ? withTail(first, composed.tail) : [first]
|
|
187
|
+
const wire = [...head, ...opening, ...rest].filter(message => message != null)
|
|
188
|
+
// Each round strips and re-marks copies: the system and project message once, and the
|
|
189
|
+
// growing conversation read back from the round before.
|
|
190
|
+
const patch = cached
|
|
191
|
+
? provider?.loopCache?.(wire as unknown as MessageFieldWithRole[], agentModel, hints)
|
|
192
|
+
: undefined
|
|
193
|
+
|
|
150
194
|
const stream = await tooled.stream(
|
|
151
|
-
[
|
|
152
|
-
{ runName: action, metadata: { purpose } },
|
|
195
|
+
(patch?.messages ?? wire) as BaseMessageLike[],
|
|
196
|
+
{ ...patch?.options, runName: action, metadata: { purpose } } as Parameters<typeof tooled.stream>[1],
|
|
153
197
|
)
|
|
154
198
|
|
|
155
199
|
let final: AIMessageChunk | undefined
|
|
@@ -157,8 +201,8 @@ export const makeAgentModel = (options: AgentOptions): AgentModel => {
|
|
|
157
201
|
final = final != null ? final.concat(chunk) : chunk
|
|
158
202
|
}
|
|
159
203
|
|
|
160
|
-
const result = new AIMessage(final!)
|
|
161
|
-
await spectate?.(messages as ModelInputItem[], result, action,
|
|
204
|
+
const result = new AIMessage(cacheHelper.withCacheTiers(final!))
|
|
205
|
+
await spectate?.(messages as ModelInputItem[], result, action, turn, startedAt, modelId)
|
|
162
206
|
|
|
163
207
|
return result
|
|
164
208
|
})
|
|
@@ -171,7 +215,7 @@ export const makeAgentModel = (options: AgentOptions): AgentModel => {
|
|
|
171
215
|
)
|
|
172
216
|
|
|
173
217
|
const agent = entrypoint(entrypointName, async (messages: BaseMessageLike[]) => {
|
|
174
|
-
let response = await ask(messages)
|
|
218
|
+
let response = await ask({ messages, turn: 0 })
|
|
175
219
|
let turn = 0
|
|
176
220
|
|
|
177
221
|
while (true) {
|
|
@@ -214,7 +258,7 @@ export const makeAgentModel = (options: AgentOptions): AgentModel => {
|
|
|
214
258
|
}))
|
|
215
259
|
|
|
216
260
|
messages = addMessages(messages, results)
|
|
217
|
-
response = await ask(messages)
|
|
261
|
+
response = await ask({ messages, turn })
|
|
218
262
|
}
|
|
219
263
|
|
|
220
264
|
return messages
|
package/src/plugins/summarize.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { compactionHelper } from '../helpers/compaction.js'
|
|
|
18
18
|
*
|
|
19
19
|
* What it contributes is rendered as clearly delimited, explicitly untrusted material. These are
|
|
20
20
|
* model words derived from user input, stored and replayed into a later prompt: they belong in the
|
|
21
|
-
*
|
|
21
|
+
* context block of the project message, described as a record of what happened, never as instructions.
|
|
22
22
|
*/
|
|
23
23
|
export const summarizePlugin = (options: SummarizeOptions = {}): AgentPlugin => {
|
|
24
24
|
const {
|
package/src/types.ts
CHANGED
|
@@ -17,11 +17,13 @@ export interface AgentToolSet { [key: string]: StructuredToolInterface }
|
|
|
17
17
|
* What the caller gets told about each model call.
|
|
18
18
|
*
|
|
19
19
|
* Shaped to match `spectate(spectator, callType)` from `@owlmeans/llm` exactly, so an application
|
|
20
|
-
* that already has a spectator passes the curried function straight in.
|
|
20
|
+
* that already has a spectator passes the curried function straight in. `retries` carries the
|
|
21
|
+
* loop's turn number, and `model` the id of the model that answered.
|
|
21
22
|
*/
|
|
22
23
|
export interface AgentSpectateHook {
|
|
23
24
|
(
|
|
24
25
|
input: ModelInputItem[], message: AIMessage, action: string, retries: number, startedAt?: number,
|
|
26
|
+
model?: string,
|
|
25
27
|
): Promise<unknown>
|
|
26
28
|
}
|
|
27
29
|
|
|
@@ -31,7 +33,10 @@ export interface AgentOptions {
|
|
|
31
33
|
/** Overrides the model resolved from the execution. */
|
|
32
34
|
agentModel?: BaseChatModel
|
|
33
35
|
tools: AgentToolSet
|
|
34
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Static context. Lands in `PromptBlock.Context` — the project message, behind the cached
|
|
38
|
+
* system region — never in the system message other runs share.
|
|
39
|
+
*/
|
|
35
40
|
context?: string[]
|
|
36
41
|
conversation?: ConversationRef
|
|
37
42
|
/** LangGraph entrypoint name; shows up in traces. */
|
|
@@ -44,7 +49,10 @@ export interface AgentOptions {
|
|
|
44
49
|
* by default: the agent holds an execution, not the service that knows its policy.
|
|
45
50
|
*/
|
|
46
51
|
utility?: () => BaseChatModel | undefined
|
|
47
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Provider plugin used for cache placement. Resolved from the model when omitted
|
|
54
|
+
* (`llmPluginRegistry.resolveFor`, so a model the service built gets its own provider's).
|
|
55
|
+
*/
|
|
48
56
|
provider?: LlmPlugin
|
|
49
57
|
maxTurns?: number
|
|
50
58
|
/**
|
|
@@ -69,7 +77,7 @@ export interface AgentOptions {
|
|
|
69
77
|
export interface AgentInvokeArgs {
|
|
70
78
|
/** LangChain `runName` for the model calls of this run. */
|
|
71
79
|
action?: string
|
|
72
|
-
/** Extra
|
|
80
|
+
/** Extra context for this run only — it joins the project message. */
|
|
73
81
|
context?: string[]
|
|
74
82
|
}
|
|
75
83
|
|
package/tests/_tools/model.ts
CHANGED
|
@@ -22,16 +22,25 @@ export interface ScriptedModel {
|
|
|
22
22
|
turns: () => number
|
|
23
23
|
/** The message lists it was asked with, in order. */
|
|
24
24
|
asked: () => unknown[][]
|
|
25
|
+
/** The call options of each ask, in order. */
|
|
26
|
+
options: () => Array<Record<string, unknown>>
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
/**
|
|
30
|
+
* `extra` puts identity on the double — a `modelName`, the `metadata.config` a service-built model
|
|
31
|
+
* carries — so a provider plugin can recognise and size it.
|
|
32
|
+
*/
|
|
33
|
+
export const scriptedModel = (script: ScriptedTurn[], extra: Record<string, unknown> = {}): ScriptedModel => {
|
|
28
34
|
let at = 0
|
|
29
35
|
const asked: unknown[][] = []
|
|
36
|
+
const options: Array<Record<string, unknown>> = []
|
|
30
37
|
|
|
31
38
|
const model = {
|
|
39
|
+
...extra,
|
|
32
40
|
bindTools: () => model,
|
|
33
|
-
stream: async (messages: unknown[]) => {
|
|
41
|
+
stream: async (messages: unknown[], callOptions: Record<string, unknown> = {}) => {
|
|
34
42
|
asked.push(messages)
|
|
43
|
+
options.push(callOptions)
|
|
35
44
|
const turn = script[Math.min(at, script.length - 1)]
|
|
36
45
|
at += 1
|
|
37
46
|
|
|
@@ -46,5 +55,5 @@ export const scriptedModel = (script: ScriptedTurn[]): ScriptedModel => {
|
|
|
46
55
|
},
|
|
47
56
|
}
|
|
48
57
|
|
|
49
|
-
return { model: model as unknown as BaseChatModel, turns: () => at, asked: () => asked }
|
|
58
|
+
return { model: model as unknown as BaseChatModel, turns: () => at, asked: () => asked, options: () => options }
|
|
50
59
|
}
|
package/tests/agent.spec.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
2
|
import { tool } from '@langchain/core/tools'
|
|
3
|
+
import type { BaseChatModel } from '@langchain/core/language_models/chat_models'
|
|
3
4
|
import * as z from 'zod'
|
|
4
|
-
import { ExecutionLevel, PromptBlock } from '@owlmeans/llm-common'
|
|
5
|
-
import { makePromptService } from '@owlmeans/llm'
|
|
6
|
-
import type { Execution, PromptService } from '@owlmeans/llm'
|
|
5
|
+
import { ExecutionLevel, ModelProvider, PromptBlock } from '@owlmeans/llm-common'
|
|
6
|
+
import { anthropicPlugin, makePromptService, openAiPlugin } from '@owlmeans/llm'
|
|
7
|
+
import type { Execution, ModelConfig, PromptService } from '@owlmeans/llm'
|
|
7
8
|
import { AgentRunStatus } from '@owlmeans/agent-common'
|
|
8
9
|
import { makeAgentModel } from '../src/index.js'
|
|
9
10
|
import type { AgentPlugin, AgentToolSet } from '../src/index.js'
|
|
@@ -115,9 +116,9 @@ describe('agent — plugins', () => {
|
|
|
115
116
|
expect((finished[0] as { status: string }).status).toBe(AgentRunStatus.Ok)
|
|
116
117
|
})
|
|
117
118
|
|
|
118
|
-
test('contributed context lands in the
|
|
119
|
-
// The
|
|
120
|
-
//
|
|
119
|
+
test('contributed context lands in the project message, never in the cached system', async () => {
|
|
120
|
+
// The system region is what every run of the persona shares. Run-specific material anywhere in
|
|
121
|
+
// it invalidates the prefix every call that shares the persona pays for.
|
|
121
122
|
const prompts = promptService()
|
|
122
123
|
const composed = await prompts.compose(
|
|
123
124
|
{ role: 'You are a test agent.', context: ['REMEMBERED CONTEXT'] },
|
|
@@ -233,8 +234,85 @@ describe('agent — finalization', () => {
|
|
|
233
234
|
|
|
234
235
|
await agent.invoke('go')
|
|
235
236
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
expect(
|
|
237
|
+
// The project message, right after the system, carries what the plugins contributed.
|
|
238
|
+
const project = String((scripted.asked()[0][1] as { content: unknown }).content)
|
|
239
|
+
expect(project).toContain('the agent version')
|
|
240
|
+
expect(project).not.toContain('the service version')
|
|
241
|
+
})
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
describe('agent — the prompt on the wire', () => {
|
|
245
|
+
const content = (message: unknown): unknown => (message as { content: unknown }).content
|
|
246
|
+
const marks = (message: unknown, key: string): number => Array.isArray(content(message))
|
|
247
|
+
? (content(message) as Array<Record<string, unknown>>).filter(block => block[key] != null).length
|
|
248
|
+
: 0
|
|
249
|
+
const long = 'x'.repeat(400)
|
|
250
|
+
const anthropicExec = (prompts: () => PromptService): Execution => ({
|
|
251
|
+
...execution(prompts), prompt: { role: `You are a test agent. ${long}`, skills: [] },
|
|
252
|
+
} as unknown as Execution)
|
|
253
|
+
|
|
254
|
+
// The system was stringified once — a JSON dump of content blocks sent as the persona.
|
|
255
|
+
test('the system goes out as text blocks, the project message second, the tail on a copy of the opening', async () => {
|
|
256
|
+
const scripted = scriptedModel([
|
|
257
|
+
{ toolCalls: [{ name: 'echo', args: { value: 'hi' } }] },
|
|
258
|
+
{ content: 'done' },
|
|
259
|
+
], { modelName: 'claude-haiku-4-5', metadata: { config: { model: 'claude-haiku-4-5', cacheMinTokens: 1 } } })
|
|
260
|
+
const prompts = promptService()
|
|
261
|
+
prompts.register({ alias: 'percall', body: 'per-call skill' })
|
|
262
|
+
const agent = makeAgentModel({
|
|
263
|
+
exec: anthropicExec(() => prompts), agentModel: scripted.model, tools: { echo }, provider: anthropicPlugin,
|
|
264
|
+
context: ['RUN FACTS'],
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
const result = await agent.invoke('use the tool')
|
|
268
|
+
|
|
269
|
+
const [first, second] = scripted.asked()
|
|
270
|
+
expect(content(first![0])).toEqual([
|
|
271
|
+
{ type: 'text', text: `You are a test agent. ${long}`, cache_control: { type: 'ephemeral' } },
|
|
272
|
+
])
|
|
273
|
+
expect(JSON.stringify(content(first![1]))).toContain('RUN FACTS')
|
|
274
|
+
expect(marks(first![1], 'cache_control')).toBe(1)
|
|
275
|
+
// Three explicit markers at most, never on the final message; the automatic one moves forward.
|
|
276
|
+
for (const round of [first!, second!]) {
|
|
277
|
+
const explicit = round.reduce<number>((sum, message) => sum + marks(message, 'cache_control'), 0)
|
|
278
|
+
expect(explicit).toBeLessThanOrEqual(3)
|
|
279
|
+
expect(marks(round[round.length - 1], 'cache_control')).toBe(0)
|
|
280
|
+
}
|
|
281
|
+
expect(scripted.options()[1]!.cache_control).toEqual({ type: 'ephemeral' })
|
|
282
|
+
expect(second!.length).toBe(first!.length + 2)
|
|
283
|
+
// The transcript keeps the opening as the caller sent it.
|
|
284
|
+
expect(result.messages[0]!.content).toBe('use the tool')
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
test('the tail rides a copy of the opening, after the payload', async () => {
|
|
288
|
+
const scripted = scriptedModel([{ content: 'ok' }])
|
|
289
|
+
const prompts = makePromptService({}, `agent-spec-prompts-${++seq}`)
|
|
290
|
+
prompts.use({ alias: 'late', compose: ctx => ctx.add(PromptBlock.Tail, 'LATE PACKAGE') })
|
|
291
|
+
const agent = makeAgentModel({ exec: execution(() => prompts), agentModel: scripted.model, tools: {} })
|
|
292
|
+
|
|
293
|
+
const result = await agent.invoke('go')
|
|
294
|
+
|
|
295
|
+
const asked = scripted.asked()[0]!
|
|
296
|
+
expect(content(asked[asked.length - 1])).toBe('go\n\nLATE PACKAGE')
|
|
297
|
+
expect(result.messages[0]!.content).toBe('go')
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
// By instance alone every ChatOpenAI is the compatible plugin's, which caches nothing; the agent
|
|
301
|
+
// resolves the provider the service built the model with.
|
|
302
|
+
test('a service-built ChatOpenAI is cached through the OpenAI plugin', async () => {
|
|
303
|
+
const scripted = scriptedModel([{ content: 'ok' }])
|
|
304
|
+
const chat = openAiPlugin.build({
|
|
305
|
+
alias: 'spec', secret: 'sk-test', callbacks: [],
|
|
306
|
+
config: { alias: 'spec', provider: ModelProvider.OpenAI, model: 'gpt-6-sol', cacheMinTokens: 1 } as ModelConfig,
|
|
307
|
+
})
|
|
308
|
+
;(chat as unknown as { bindTools: () => BaseChatModel }).bindTools = () => scripted.model
|
|
309
|
+
const agent = makeAgentModel({
|
|
310
|
+
exec: anthropicExec(promptService), agentModel: chat, tools: {}, context: ['RUN FACTS'],
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
await agent.invoke('go')
|
|
314
|
+
|
|
315
|
+
expect(JSON.stringify(scripted.asked()[0])).toContain('prompt_cache_breakpoint')
|
|
316
|
+
expect(scripted.options()[0]!.promptCacheOptions).toEqual({ mode: 'explicit' })
|
|
239
317
|
})
|
|
240
318
|
})
|