@spendgraph/workflows 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/noesis/execute/index.d.ts +1 -1
- package/dist/noesis/execute/index.js +1 -1
- package/dist/noesis/execute/spend.d.ts +10 -1
- package/dist/noesis/execute/spend.js +9 -1
- package/dist/noesis/index.d.ts +2 -1
- package/dist/noesis/index.js +1 -1
- package/dist/noesis/run/ledger.d.ts +10 -2
- package/dist/noesis/run/options.d.ts +14 -1
- package/dist/noesis/run/options.js +8 -0
- package/dist/noesis/run/produce.js +2 -1
- package/dist/noesis/run/stages/classify.js +2 -2
- package/dist/noesis/run/stages/direct.js +2 -1
- package/dist/noesis/run/stages/retrieve.js +6 -2
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -96,7 +96,9 @@ and win where both are set.
|
|
|
96
96
|
**`params` does not follow a model it was not written for.** A stage naming its
|
|
97
97
|
own `model` gets its own `params` or none: Haiku takes `temperature`, Sonnet 5
|
|
98
98
|
rejects it outright, and one shared request body fails on whichever it was not
|
|
99
|
-
written for. A stage overriding only `params` still merges over `stage
|
|
99
|
+
written for. A stage overriding only `params` still merges over `stage` — except
|
|
100
|
+
`answer`, which escalates through tiers, so its `params` reach it only alongside
|
|
101
|
+
a `model`.
|
|
100
102
|
|
|
101
103
|
## What a run cost
|
|
102
104
|
|
|
@@ -2,4 +2,4 @@ export { DEFAULT_TOOLS, execute } from "./execute.js";
|
|
|
2
2
|
export { order } from "./order.js";
|
|
3
3
|
export type { ExecuteOptions, Execution, SubAnswer, Waves, Wiring } from "./types.js";
|
|
4
4
|
export type { ToolSpend, ToolUsage } from "./spend.js";
|
|
5
|
-
export { addToolSpend, NO_TOOL_SPEND, readToolUsage, toolSpendOf } from "./spend.js";
|
|
5
|
+
export { addToolSpend, NO_TOOL_SPEND, readToolUsage, recorded, toolSpendOf } from "./spend.js";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { DEFAULT_TOOLS, execute } from "./execute.js";
|
|
2
2
|
export { order } from "./order.js";
|
|
3
|
-
export { addToolSpend, NO_TOOL_SPEND, readToolUsage, toolSpendOf } from "./spend.js";
|
|
3
|
+
export { addToolSpend, NO_TOOL_SPEND, readToolUsage, recorded, toolSpendOf } from "./spend.js";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import type { SubAnswer, Wiring } from "./types.js";
|
|
1
|
+
import type { Execution, SubAnswer, Wiring } from "./types.js";
|
|
2
2
|
import type { SubQuestionTool } from "../producers/decompose/index.js";
|
|
3
3
|
/** What one tool reported it cost, keyed by the tool that reported it. */
|
|
4
4
|
export interface ToolSpend {
|
|
5
|
+
/** Tool calls that ran, whether or not the tool priced itself. */
|
|
5
6
|
calls: number;
|
|
6
7
|
/** Summed where a tool priced itself. Undefined where none did. */
|
|
7
8
|
costMicros?: number;
|
|
@@ -34,3 +35,11 @@ export declare function readToolUsage(result: unknown): Omit<ToolUsage, "calls">
|
|
|
34
35
|
export declare function toolSpendOf(answers: SubAnswer[], wiring?: Partial<Record<SubQuestionTool, Wiring>>): ToolSpend;
|
|
35
36
|
/** Two executions' tool spend, added. A retry does not refund the first attempt. */
|
|
36
37
|
export declare function addToolSpend(a: ToolSpend, b: ToolSpend): ToolSpend;
|
|
38
|
+
/**
|
|
39
|
+
* The execution as the ledger should keep it: everything but the billing.
|
|
40
|
+
*
|
|
41
|
+
* Stage 4's artifact is serialized into every later stage's prompt and into the
|
|
42
|
+
* answer's evidence, so what a tool cost would ride along as citable material
|
|
43
|
+
* and be paid for again in tokens at each stage that reads it.
|
|
44
|
+
*/
|
|
45
|
+
export declare function recorded(execution: Execution): Omit<Execution, "spend">;
|
|
@@ -26,10 +26,11 @@ export function toolSpendOf(answers, wiring = {}) {
|
|
|
26
26
|
let calls = 0;
|
|
27
27
|
let costMicros;
|
|
28
28
|
for (const answer of answers) {
|
|
29
|
+
if (answer.status === "answered")
|
|
30
|
+
calls++;
|
|
29
31
|
const one = readToolUsage(answer.result);
|
|
30
32
|
if (!one)
|
|
31
33
|
continue;
|
|
32
|
-
calls++;
|
|
33
34
|
const named = wiring[answer.tool]?.name ?? answer.tool;
|
|
34
35
|
const prior = byTool[named] ?? {
|
|
35
36
|
calls: 0,
|
|
@@ -77,3 +78,10 @@ export function addToolSpend(a, b) {
|
|
|
77
78
|
: undefined;
|
|
78
79
|
return { calls: a.calls + b.calls, byTool, ...(costMicros !== undefined ? { costMicros } : {}) };
|
|
79
80
|
}
|
|
81
|
+
export function recorded(execution) {
|
|
82
|
+
return {
|
|
83
|
+
answers: execution.answers,
|
|
84
|
+
unresolved: execution.unresolved,
|
|
85
|
+
toolMs: execution.toolMs,
|
|
86
|
+
};
|
|
87
|
+
}
|
package/dist/noesis/index.d.ts
CHANGED
|
@@ -6,7 +6,8 @@ export { assemble, render as renderDraft } from "./draft/index.js";
|
|
|
6
6
|
export type { Emit, EventBase, NoesisEvent, NoesisEventInput } from "./events.js";
|
|
7
7
|
export { emitter } from "./events.js";
|
|
8
8
|
export type { ExecuteOptions, Execution, SubAnswer, Waves, Wiring, } from "./execute/index.js";
|
|
9
|
-
export {
|
|
9
|
+
export type { ToolSpend, ToolUsage } from "./execute/index.js";
|
|
10
|
+
export { addToolSpend, DEFAULT_TOOLS, execute, NO_TOOL_SPEND, order, readToolUsage, recorded, toolSpendOf, } from "./execute/index.js";
|
|
10
11
|
export type { ClosureChecklist, ClosureChecklistInput, ClosureChecklistOptions, ClosureChecklistResult, ClosureGate, } from "./gates/closure-checklist/index.js";
|
|
11
12
|
export { invoke as closureChecklist } from "./gates/closure-checklist/index.js";
|
|
12
13
|
export type { CqotGate, CqotGateInput, CqotGateOptions, CqotGateResult, Gate, GateQuestion, GateVerdict, } from "./gates/cqot-gate/index.js";
|
package/dist/noesis/index.js
CHANGED
|
@@ -2,7 +2,7 @@ export { stageCited, unattributed } from "./attribution.js";
|
|
|
2
2
|
export { asked } from "./context.js";
|
|
3
3
|
export { assemble, render as renderDraft } from "./draft/index.js";
|
|
4
4
|
export { emitter } from "./events.js";
|
|
5
|
-
export { DEFAULT_TOOLS, execute, order } from "./execute/index.js";
|
|
5
|
+
export { addToolSpend, DEFAULT_TOOLS, execute, NO_TOOL_SPEND, order, readToolUsage, recorded, toolSpendOf, } from "./execute/index.js";
|
|
6
6
|
export { invoke as closureChecklist } from "./gates/closure-checklist/index.js";
|
|
7
7
|
export { invoke as cqotGate } from "./gates/cqot-gate/index.js";
|
|
8
8
|
export { invoke as premortem } from "./gates/premortem/index.js";
|
|
@@ -51,8 +51,15 @@ export declare const STAGE_KEYS: {
|
|
|
51
51
|
readonly "6C": "answer";
|
|
52
52
|
readonly R: "root_cause";
|
|
53
53
|
};
|
|
54
|
-
/**
|
|
55
|
-
|
|
54
|
+
/** Stages that dispatch or pair rather than call a model. */
|
|
55
|
+
type CodeOnly = "execution" | "verification" | "discriminating_test";
|
|
56
|
+
/**
|
|
57
|
+
* A stage by the key a config names it under.
|
|
58
|
+
*
|
|
59
|
+
* The code-only stages are excluded: naming a model for the tool dispatcher or
|
|
60
|
+
* the blind-check pairing would typecheck and do nothing.
|
|
61
|
+
*/
|
|
62
|
+
export type StageKey = Exclude<(typeof STAGE_KEYS)[StageId], CodeOnly>;
|
|
56
63
|
/** What one stage left behind, and what it cost. */
|
|
57
64
|
export interface Entry extends Usage {
|
|
58
65
|
stage: StageId;
|
|
@@ -156,3 +163,4 @@ export interface Ledger {
|
|
|
156
163
|
* failing once each are the same amount of a run going nowhere.
|
|
157
164
|
*/
|
|
158
165
|
export declare function newLedger(maxRetries?: number, emit?: Emit): Ledger;
|
|
166
|
+
export {};
|
|
@@ -7,5 +7,18 @@ import { type StageId } from "./ledger.js";
|
|
|
7
7
|
* rather than inherited when the stage names a model of its own.
|
|
8
8
|
*/
|
|
9
9
|
export declare function stageOptionsFor(opts: NoesisOptions, id: StageId): StageOptions;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Triage's options: `stages.triage` under `opts.triage`.
|
|
12
|
+
*
|
|
13
|
+
* `stage` is deliberately not a base here — it is the model for the stages
|
|
14
|
+
* between triage and the answer, and folding it in would send triage a body
|
|
15
|
+
* written for a different model.
|
|
16
|
+
*/
|
|
17
|
+
export declare function triageOptions(opts: NoesisOptions): StageOptions;
|
|
18
|
+
/**
|
|
19
|
+
* The answer's tiers, defaulting to whatever `stages.answer` named.
|
|
20
|
+
*
|
|
21
|
+
* `params` reaches the answer only alongside a `model`, because the answer
|
|
22
|
+
* escalates through tiers and a tier carries its own params.
|
|
23
|
+
*/
|
|
11
24
|
export declare function answerOptions(opts: NoesisOptions): AnswerOptions;
|
|
@@ -9,6 +9,14 @@ export function stageOptionsFor(opts, id) {
|
|
|
9
9
|
const rest = Object.fromEntries(Object.entries({ ...base, ...per }).filter(([field]) => field !== "params"));
|
|
10
10
|
return params && Object.keys(params).length > 0 ? { ...rest, params } : rest;
|
|
11
11
|
}
|
|
12
|
+
export function triageOptions(opts) {
|
|
13
|
+
const per = opts.stages?.[STAGE_KEYS["0"]] ?? {};
|
|
14
|
+
const own = opts.triage ?? {};
|
|
15
|
+
const ownModel = own.model !== undefined && own.model !== per.model;
|
|
16
|
+
const params = ownModel ? own.params : { ...per.params, ...own.params };
|
|
17
|
+
const rest = Object.fromEntries(Object.entries({ ...per, ...own }).filter(([field]) => field !== "params"));
|
|
18
|
+
return params && Object.keys(params).length > 0 ? { ...rest, params } : rest;
|
|
19
|
+
}
|
|
12
20
|
export function answerOptions(opts) {
|
|
13
21
|
const base = opts.answer ?? {};
|
|
14
22
|
const sixC = opts.stages?.[STAGE_KEYS["6C"]];
|
|
@@ -8,6 +8,7 @@ import { NoToolsError } from "./errors.js";
|
|
|
8
8
|
import { plan } from "./plan.js";
|
|
9
9
|
import { stageOptionsFor } from "./options.js";
|
|
10
10
|
import { NO_TOOL_SPEND } from "../execute/spend.js";
|
|
11
|
+
import { recorded } from "../execute/index.js";
|
|
11
12
|
import { recordToolSpend } from "./state.js";
|
|
12
13
|
export const soFar = (state, question) => JSON.stringify({ question, ...digest(state.ledger.artifacts()) }, null, 2);
|
|
13
14
|
export async function frame(client, llm, question, opts, state) {
|
|
@@ -37,7 +38,7 @@ export async function work(client, llm, question, opts, state, split) {
|
|
|
37
38
|
const execution = await execute(opts.tools, split.sub_questions, { emit: state.emit });
|
|
38
39
|
recordToolSpend(state, execution.spend);
|
|
39
40
|
state.ledger.record("4", {
|
|
40
|
-
data: execution,
|
|
41
|
+
data: recorded(execution),
|
|
41
42
|
rolloutIds: [],
|
|
42
43
|
model: "",
|
|
43
44
|
inputTokens: 0,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { routeFor } from "../../route.js";
|
|
2
2
|
import { invoke as triage } from "../../router/triage/index.js";
|
|
3
3
|
import { nextTask } from "../state.js";
|
|
4
|
-
import {
|
|
4
|
+
import { triageOptions } from "../options.js";
|
|
5
5
|
export const classifyStage = (client, llm, question, opts, state) => async () => {
|
|
6
|
-
const stage = await triage(client, llm, { ...opts.triage, currentTask: state.currentTask, question },
|
|
6
|
+
const stage = await triage(client, llm, { ...opts.triage, currentTask: state.currentTask, question }, triageOptions(opts));
|
|
7
7
|
state.estimates = state.ledger.record("0", { ...stage, data: stage.estimates });
|
|
8
8
|
state.routing = routeFor(stage.estimates);
|
|
9
9
|
state.currentTask = nextTask(stage.estimates, state.currentTask);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { answer } from "../../producers/toulmin/index.js";
|
|
2
|
+
import { answerOptions } from "../options.js";
|
|
2
3
|
export const directStage = (client, llm, question, opts, state) => async () => {
|
|
3
|
-
const answered = await answer(client, llm, { question, ...state.ledger.artifacts() }, opts
|
|
4
|
+
const answered = await answer(client, llm, { question, ...state.ledger.artifacts() }, answerOptions(opts));
|
|
4
5
|
state.answered = answered;
|
|
5
6
|
state.text = state.ledger.record("6C", { ...answered, data: answered.answer }).claim;
|
|
6
7
|
return state.text;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { execute } from "../../execute/index.js";
|
|
2
2
|
import { answer } from "../../producers/toulmin/index.js";
|
|
3
3
|
import { NoToolsError } from "../errors.js";
|
|
4
|
+
import { answerOptions } from "../options.js";
|
|
5
|
+
import { recorded } from "../../execute/index.js";
|
|
6
|
+
import { recordToolSpend } from "../state.js";
|
|
4
7
|
const DEFAULT_TOOL = "deeprecall";
|
|
5
8
|
const lookup = (question, tool) => ({
|
|
6
9
|
id: "q",
|
|
@@ -15,15 +18,16 @@ export const retrieveStage = (client, llm, question, opts, state) => async () =>
|
|
|
15
18
|
if (!opts.tools)
|
|
16
19
|
throw new NoToolsError();
|
|
17
20
|
const execution = await execute(opts.tools, [lookup(question, opts.retrieve?.tool ?? DEFAULT_TOOL)], { emit: state.emit });
|
|
21
|
+
recordToolSpend(state, execution.spend);
|
|
18
22
|
state.ledger.record("4", {
|
|
19
|
-
data: execution,
|
|
23
|
+
data: recorded(execution),
|
|
20
24
|
rolloutIds: [],
|
|
21
25
|
model: "",
|
|
22
26
|
inputTokens: 0,
|
|
23
27
|
outputTokens: 0,
|
|
24
28
|
latencyMs: execution.toolMs,
|
|
25
29
|
});
|
|
26
|
-
const answered = await answer(client, llm, { question, ...state.ledger.artifacts() }, opts
|
|
30
|
+
const answered = await answer(client, llm, { question, ...state.ledger.artifacts() }, answerOptions(opts));
|
|
27
31
|
state.answered = answered;
|
|
28
32
|
state.text = state.ledger.record("6C", { ...answered, data: answered.answer }).claim;
|
|
29
33
|
return state.text;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spendgraph/workflows",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Ready-made workflows assembled from the spendgraph packages.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"README.md"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@spendgraph/harness": "^0.3.
|
|
37
|
-
"@spendgraph/llms": "^0.3.
|
|
38
|
-
"@spendgraph/prompt": "^0.3.
|
|
39
|
-
"@spendgraph/tools": "^0.3.
|
|
36
|
+
"@spendgraph/harness": "^0.3.1",
|
|
37
|
+
"@spendgraph/llms": "^0.3.1",
|
|
38
|
+
"@spendgraph/prompt": "^0.3.1",
|
|
39
|
+
"@spendgraph/tools": "^0.3.1"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "tsc -p tsconfig.json --emitDeclarationOnly && tsc -p tsconfig.json --declaration false --removeComments",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@locusgraph/client": "^0.8.1",
|
|
50
|
-
"@spendgraph/evals": "^0.3.
|
|
50
|
+
"@spendgraph/evals": "^0.3.1",
|
|
51
51
|
"typescript": "^5"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|