@spendgraph/harness 0.1.0
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 +162 -0
- package/bin/harness.mjs +76 -0
- package/dist/core/budget.d.ts +46 -0
- package/dist/core/budget.js +72 -0
- package/dist/core/cache.d.ts +119 -0
- package/dist/core/cache.js +206 -0
- package/dist/core/client.d.ts +33 -0
- package/dist/core/client.js +98 -0
- package/dist/core/errors.d.ts +22 -0
- package/dist/core/errors.js +28 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +5 -0
- package/dist/core/pull.d.ts +17 -0
- package/dist/core/pull.js +38 -0
- package/dist/core/schema/serialize.d.ts +12 -0
- package/dist/core/schema/serialize.js +42 -0
- package/dist/core/schema/types.d.ts +58 -0
- package/dist/core/schema/types.js +1 -0
- package/dist/core/schema/validate.d.ts +28 -0
- package/dist/core/schema/validate.js +98 -0
- package/dist/harness.d.ts +128 -0
- package/dist/harness.js +187 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/prompt/codegen.d.ts +37 -0
- package/dist/prompt/codegen.js +97 -0
- package/dist/prompt/render.d.ts +35 -0
- package/dist/prompt/render.js +66 -0
- package/dist/prompt/run.d.ts +38 -0
- package/dist/prompt/run.js +96 -0
- package/dist/prompt/types.d.ts +156 -0
- package/dist/prompt/types.js +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type { FieldSpec } from "../core/schema/types.js";
|
|
2
|
+
import type { Block, Message } from "./render.js";
|
|
3
|
+
/** What `GET /api/v1/prompts/:id` returns, narrowed to what this package uses. */
|
|
4
|
+
export interface PromptPayload {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
/** The handle this prompt can also be pulled by. Absent before the server
|
|
8
|
+
* that adds it; null on a row the backfill could not slug. */
|
|
9
|
+
slug?: string | null;
|
|
10
|
+
blocks: Block[];
|
|
11
|
+
question: string;
|
|
12
|
+
models: string[];
|
|
13
|
+
temperature: number;
|
|
14
|
+
maxTokens: number;
|
|
15
|
+
fieldSpec: FieldSpec[];
|
|
16
|
+
currentVersionId: string | null;
|
|
17
|
+
}
|
|
18
|
+
/** A pulled prompt: its declarations, its version, and how to render it. */
|
|
19
|
+
export interface Prompt {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
/** What `pull` accepts besides the id. Null when the prompt has none. */
|
|
23
|
+
slug: string | null;
|
|
24
|
+
fields: FieldSpec[];
|
|
25
|
+
/** What a rollout recorded from this prompt should reference. */
|
|
26
|
+
versionId: string | null;
|
|
27
|
+
models: string[];
|
|
28
|
+
/** Validates and substitutes, throwing on a missing required field. */
|
|
29
|
+
render(values?: Record<string, unknown>): Message[];
|
|
30
|
+
/** The serialised field map that `render` used — recorded on the rollout. */
|
|
31
|
+
serialize(values?: Record<string, unknown>): Record<string, string>;
|
|
32
|
+
}
|
|
33
|
+
/** What the caller hands back after running the prompt themselves. */
|
|
34
|
+
export interface ReportInput {
|
|
35
|
+
/** Dedupe key. Generated if omitted; supply your own to make a retry safe. */
|
|
36
|
+
rolloutId?: string;
|
|
37
|
+
versionId?: string | null;
|
|
38
|
+
model: string;
|
|
39
|
+
fields: Record<string, string>;
|
|
40
|
+
rendered: Message[];
|
|
41
|
+
output: string;
|
|
42
|
+
status?: "completed" | "failed";
|
|
43
|
+
error?: string;
|
|
44
|
+
inputTokens?: number;
|
|
45
|
+
outputTokens?: number;
|
|
46
|
+
cacheReadTokens?: number;
|
|
47
|
+
cacheWriteTokens?: number;
|
|
48
|
+
latencyMs?: number;
|
|
49
|
+
/** Set only for evaluation rollouts. Production traffic leaves it unset. */
|
|
50
|
+
caseId?: string;
|
|
51
|
+
seed?: number;
|
|
52
|
+
candidateId?: string;
|
|
53
|
+
parentId?: string;
|
|
54
|
+
generation?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface Rollout {
|
|
57
|
+
rolloutId: string;
|
|
58
|
+
status: "completed" | "failed";
|
|
59
|
+
output: string;
|
|
60
|
+
costMicros: number;
|
|
61
|
+
latencyMs: number;
|
|
62
|
+
inputTokens: number;
|
|
63
|
+
outputTokens: number;
|
|
64
|
+
}
|
|
65
|
+
/** Run configuration. Field values are the second argument, not part of this. */
|
|
66
|
+
export interface RunOptions {
|
|
67
|
+
/** Overrides the prompt's first saved model. Never silently defaulted. */
|
|
68
|
+
model?: string;
|
|
69
|
+
temperature?: number;
|
|
70
|
+
maxTokens?: number;
|
|
71
|
+
/** Which repetition this is. Metadata for pass^k, not a provider parameter. */
|
|
72
|
+
seed?: number;
|
|
73
|
+
/** Links the run to a dataset case; the server resolves the split from it. */
|
|
74
|
+
caseId?: string;
|
|
75
|
+
candidateId?: string;
|
|
76
|
+
parentId?: string;
|
|
77
|
+
generation?: number;
|
|
78
|
+
/** Supply to make your own retry idempotent. Generated when omitted. */
|
|
79
|
+
rolloutId?: string;
|
|
80
|
+
/** false runs the model but writes nothing — for debugging, not datasets. */
|
|
81
|
+
record?: boolean;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Prompt id → the values that prompt expects.
|
|
85
|
+
*
|
|
86
|
+
* Empty here and filled in by the file `harness codegen` writes, through
|
|
87
|
+
* declaration merging. Left empty, every id falls back to a loose value map —
|
|
88
|
+
* so the package works with no codegen step, and a stale generated file
|
|
89
|
+
* degrades to permissive rather than wrong.
|
|
90
|
+
*/
|
|
91
|
+
export interface Prompts {
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The values type for a known prompt id, or a loose map for anything else.
|
|
95
|
+
*
|
|
96
|
+
* A conditional rather than an overload: overloads would let a call with the
|
|
97
|
+
* wrong values silently fall through to the permissive signature, which is
|
|
98
|
+
* exactly the mistake codegen exists to catch.
|
|
99
|
+
*/
|
|
100
|
+
export type ValuesFor<K extends string> = K extends keyof Prompts ? Prompts[K] : Record<string, unknown>;
|
|
101
|
+
/** One wording a prompt has had. */
|
|
102
|
+
export interface PromptVersion {
|
|
103
|
+
id: string;
|
|
104
|
+
promptId: string;
|
|
105
|
+
hash: string;
|
|
106
|
+
blocks: Block[];
|
|
107
|
+
question: string;
|
|
108
|
+
fieldSpec: FieldSpec[] | null;
|
|
109
|
+
/** "user" is a wording a person wrote; "assay" is one the optimizer proposed. */
|
|
110
|
+
origin: "user" | "assay";
|
|
111
|
+
candidateId: string | null;
|
|
112
|
+
parentVersionId: string | null;
|
|
113
|
+
/** Last time this wording was put live; null means it never has been. */
|
|
114
|
+
servedAt?: string | null;
|
|
115
|
+
/** How many stints it has had live. */
|
|
116
|
+
servedCount?: number;
|
|
117
|
+
createdAt: string;
|
|
118
|
+
isCurrent: boolean;
|
|
119
|
+
}
|
|
120
|
+
export type Split = "feedback" | "held_out";
|
|
121
|
+
/** One input the prompt is evaluated against. */
|
|
122
|
+
export interface DatasetCase {
|
|
123
|
+
caseId: string;
|
|
124
|
+
fieldValues: Record<string, string>;
|
|
125
|
+
expected?: string | null;
|
|
126
|
+
/**
|
|
127
|
+
* Omit it. The server derives the split from the case id so a case never moves
|
|
128
|
+
* between sides; supply one only when importing a set that already carries it.
|
|
129
|
+
*/
|
|
130
|
+
split?: Split;
|
|
131
|
+
}
|
|
132
|
+
export interface DatasetSummary {
|
|
133
|
+
cases: (DatasetCase & {
|
|
134
|
+
split: Split;
|
|
135
|
+
})[];
|
|
136
|
+
counts: {
|
|
137
|
+
total: number;
|
|
138
|
+
feedback: number;
|
|
139
|
+
held_out: number;
|
|
140
|
+
};
|
|
141
|
+
/** Why this dataset cannot be optimized against yet, or null. */
|
|
142
|
+
problem: string | null;
|
|
143
|
+
}
|
|
144
|
+
/** A rollout as the run route returns it. `id` is null for a dry run. */
|
|
145
|
+
export interface RunResult {
|
|
146
|
+
id: string | null;
|
|
147
|
+
model: string;
|
|
148
|
+
status: "completed" | "failed";
|
|
149
|
+
output: string;
|
|
150
|
+
error?: string | null;
|
|
151
|
+
costMicros: number;
|
|
152
|
+
latencyMs: number;
|
|
153
|
+
inputTokens: number;
|
|
154
|
+
outputTokens: number;
|
|
155
|
+
seed?: number;
|
|
156
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@spendgraph/harness",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Pull a stored prompt, render it, report what it cost. Zero dependencies.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/fnLog0/spendgraph.git",
|
|
9
|
+
"directory": "packages/harness"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"llm",
|
|
13
|
+
"prompt",
|
|
14
|
+
"prompt-management",
|
|
15
|
+
"cost",
|
|
16
|
+
"evals"
|
|
17
|
+
],
|
|
18
|
+
"type": "module",
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./core": {
|
|
27
|
+
"types": "./dist/core/index.d.ts",
|
|
28
|
+
"import": "./dist/core/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./package.json": "./package.json"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"bin",
|
|
34
|
+
"dist",
|
|
35
|
+
"README.md"
|
|
36
|
+
],
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.json",
|
|
39
|
+
"test": "npm run build && vitest run"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"typescript": "^5"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"bin": {
|
|
51
|
+
"harness": "bin/harness.mjs"
|
|
52
|
+
}
|
|
53
|
+
}
|