@wrenautomation/raven 0.0.0-stage → 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/LICENSE.md +91 -0
- package/README.md +52 -2
- package/dist/app/cli.d.ts +2 -0
- package/dist/app/cli.js +115 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/model.d.ts +20 -0
- package/dist/model.js +68 -0
- package/dist/plan.d.ts +31 -0
- package/dist/plan.js +90 -0
- package/dist/plans/index.d.ts +8 -0
- package/dist/plans/index.js +196 -0
- package/dist/render.d.ts +7 -0
- package/dist/render.js +40 -0
- package/dist/review.d.ts +11 -0
- package/dist/review.js +44 -0
- package/dist/triage.d.ts +15 -0
- package/dist/triage.js +65 -0
- package/dist/types.d.ts +265 -0
- package/dist/types.js +134 -0
- package/package.json +50 -4
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default plan file per ask kind. A copy of one, tuned and stored beside a ledger, is how
|
|
3
|
+
* a run learns: the recipe changes, raven does not. `raven plans <kind>` prints one to start from.
|
|
4
|
+
*/
|
|
5
|
+
import { PlanFile as PlanFileShape } from "../types.js";
|
|
6
|
+
const SHAPE_QUERIES = `Return ONLY a JSON object, no prose, exactly this shape:
|
|
7
|
+
{"queries": [{"terms": "...", "why": "..."}]}`;
|
|
8
|
+
const SHAPE_HITS = `Return ONLY a JSON object, no prose, exactly this shape:
|
|
9
|
+
{"hits": [{"url": "...", "read": true, "why": "..."}]}`;
|
|
10
|
+
const SHAPE_EDGE = `Return ONLY a JSON object, no prose, exactly this shape:
|
|
11
|
+
{"next": "stop", "why": "..."}
|
|
12
|
+
where "next" is "stop", "again" (a new round from plan) or "back" (rerun one step of this round, named in "to": "plan", "fetch", "read" or "extract").`;
|
|
13
|
+
const CONTEXT = `Ask: {ask}
|
|
14
|
+
Known already (look past these):
|
|
15
|
+
{known}
|
|
16
|
+
What yielded before (hits, reads, proposed, kept):
|
|
17
|
+
{yield}`;
|
|
18
|
+
const TRIAGE_RULES = `- One entry per hit, with its url as given. Mark "read": true for at most {n}.
|
|
19
|
+
- Read a hit when what it shows for free (title, snippet, channel, length, date) says it holds what the ask needs and is not known already.
|
|
20
|
+
- A hit returned by more than one source is a good sign, not a duplicate.
|
|
21
|
+
- "why" is one short line a person reads to agree or not.`;
|
|
22
|
+
const REVIEW = `You decide what happens after one round of research.
|
|
23
|
+
|
|
24
|
+
${SHAPE_EDGE}
|
|
25
|
+
|
|
26
|
+
Rules:
|
|
27
|
+
- "stop" when the found lines answer the ask, or when another round would likely add nothing.
|
|
28
|
+
- "again" when the ask is still open and new queries could find more. Say what to look for next in "why".
|
|
29
|
+
- "back" when one step of this round failed for a reason a rerun fixes (a source was down, reads timed out). Name the step in "to".
|
|
30
|
+
- "why" is one short line a person reads to agree or not.
|
|
31
|
+
|
|
32
|
+
Ask: {ask}
|
|
33
|
+
Round {round} of at most {rounds}. Hits {hits}, reads {reads}, findings proposed {proposed}, kept {kept}.
|
|
34
|
+
Found:
|
|
35
|
+
{found}
|
|
36
|
+
Notes:
|
|
37
|
+
{notes}`;
|
|
38
|
+
const web = {
|
|
39
|
+
id: "raven/web",
|
|
40
|
+
kind: "web",
|
|
41
|
+
version: 1,
|
|
42
|
+
propose: `You plan web searches for one research ask.
|
|
43
|
+
|
|
44
|
+
${SHAPE_QUERIES}
|
|
45
|
+
|
|
46
|
+
Rules:
|
|
47
|
+
- At most {n} queries, each 3 to 10 words, as a person types into a search engine.
|
|
48
|
+
- Each query finds a different kind of source: a survey or benchmark with numbers, a trade publication or industry association, people in the field talking (forums, Reddit, reviews), a government statistic.
|
|
49
|
+
- "why" says in one short line what the query would add that is not known yet.
|
|
50
|
+
- Put a year in a query only when fresh numbers matter. This year is {year}.
|
|
51
|
+
- No site: operators. Quotes only around a phrase that must match exactly.
|
|
52
|
+
|
|
53
|
+
${CONTEXT}`,
|
|
54
|
+
triage: `You decide which search hits to read for one research ask. A read costs time; a skip costs nothing.
|
|
55
|
+
|
|
56
|
+
${SHAPE_HITS}
|
|
57
|
+
|
|
58
|
+
Rules:
|
|
59
|
+
${TRIAGE_RULES}
|
|
60
|
+
- Prefer primary sources and people in the field over listicles and aggregators.
|
|
61
|
+
|
|
62
|
+
${CONTEXT}
|
|
63
|
+
Hits:
|
|
64
|
+
{hits}`,
|
|
65
|
+
review: REVIEW,
|
|
66
|
+
sources: ["searxng", "exa", "google"],
|
|
67
|
+
budget: { queries: 3, reads: 6, rounds: 3 },
|
|
68
|
+
};
|
|
69
|
+
const video = {
|
|
70
|
+
id: "raven/video",
|
|
71
|
+
kind: "video",
|
|
72
|
+
version: 1,
|
|
73
|
+
propose: `You plan video searches for one research ask: talks, walkthroughs, interviews and reviews on YouTube and podcast feeds.
|
|
74
|
+
|
|
75
|
+
${SHAPE_QUERIES}
|
|
76
|
+
|
|
77
|
+
Rules:
|
|
78
|
+
- At most {n} queries, each 2 to 8 words, as a person types into a video search box.
|
|
79
|
+
- Each query reaches a different kind of speaker: a practitioner showing their work, a conference talk, an interview or podcast, a critic or reviewer.
|
|
80
|
+
- "why" says in one short line what the query would add that is not known yet.
|
|
81
|
+
- This year is {year}; add it only when the topic moves fast.
|
|
82
|
+
|
|
83
|
+
${CONTEXT}`,
|
|
84
|
+
triage: `You decide which videos to read (transcript and screen) for one research ask. A read costs minutes per video; a skip costs nothing.
|
|
85
|
+
|
|
86
|
+
${SHAPE_HITS}
|
|
87
|
+
|
|
88
|
+
Rules:
|
|
89
|
+
${TRIAGE_RULES}
|
|
90
|
+
- Length is in seconds. Skip a clip under 60 seconds unless the ask is about short-form video. Prefer 5 to 60 minutes.
|
|
91
|
+
- A channel that yielded nothing before is a reason to skip.
|
|
92
|
+
|
|
93
|
+
${CONTEXT}
|
|
94
|
+
Hits:
|
|
95
|
+
{hits}`,
|
|
96
|
+
review: REVIEW,
|
|
97
|
+
sources: ["youtube", "podcasts"],
|
|
98
|
+
budget: { queries: 3, reads: 4, rounds: 2 },
|
|
99
|
+
};
|
|
100
|
+
const channel = {
|
|
101
|
+
id: "raven/channel",
|
|
102
|
+
kind: "channel",
|
|
103
|
+
version: 1,
|
|
104
|
+
propose: `You plan searches that find the people and channels worth following for one research ask: creators, newsletters, podcasts, forums.
|
|
105
|
+
|
|
106
|
+
${SHAPE_QUERIES}
|
|
107
|
+
|
|
108
|
+
Rules:
|
|
109
|
+
- At most {n} queries, each 3 to 10 words.
|
|
110
|
+
- Each query finds a different kind of channel: a creator on video, a writer or newsletter, a podcast, a community.
|
|
111
|
+
- "why" says in one short line what the query would add that is not known yet.
|
|
112
|
+
|
|
113
|
+
${CONTEXT}`,
|
|
114
|
+
triage: `You decide which channel pages to read for one research ask: a profile, an about page, a feed. A read costs time; a skip costs nothing.
|
|
115
|
+
|
|
116
|
+
${SHAPE_HITS}
|
|
117
|
+
|
|
118
|
+
Rules:
|
|
119
|
+
${TRIAGE_RULES}
|
|
120
|
+
- Prefer the channel's own page over a page about it.
|
|
121
|
+
|
|
122
|
+
${CONTEXT}
|
|
123
|
+
Hits:
|
|
124
|
+
{hits}`,
|
|
125
|
+
review: REVIEW,
|
|
126
|
+
sources: ["searxng", "youtube", "exa"],
|
|
127
|
+
budget: { queries: 3, reads: 6, rounds: 2 },
|
|
128
|
+
};
|
|
129
|
+
const person = {
|
|
130
|
+
id: "raven/person",
|
|
131
|
+
kind: "person",
|
|
132
|
+
version: 1,
|
|
133
|
+
propose: `You plan searches about one person or company for one research ask: what they do, what they said, what others say about them.
|
|
134
|
+
|
|
135
|
+
${SHAPE_QUERIES}
|
|
136
|
+
|
|
137
|
+
Rules:
|
|
138
|
+
- At most {n} queries, each 3 to 10 words. Name the person or company in each, as written in the ask.
|
|
139
|
+
- Each query finds a different kind of page: their own site or profile, an interview or talk, press or reviews, a filing or directory.
|
|
140
|
+
- "why" says in one short line what the query would add that is not known yet.
|
|
141
|
+
- No site: operators.
|
|
142
|
+
|
|
143
|
+
${CONTEXT}`,
|
|
144
|
+
triage: `You decide which pages about one person or company to read for one research ask. A read costs time; a skip costs nothing.
|
|
145
|
+
|
|
146
|
+
${SHAPE_HITS}
|
|
147
|
+
|
|
148
|
+
Rules:
|
|
149
|
+
${TRIAGE_RULES}
|
|
150
|
+
- Skip a page about a different person or company with the same name.
|
|
151
|
+
- Prefer what they wrote or said over what a directory copied.
|
|
152
|
+
|
|
153
|
+
${CONTEXT}
|
|
154
|
+
Hits:
|
|
155
|
+
{hits}`,
|
|
156
|
+
review: REVIEW,
|
|
157
|
+
sources: ["searxng", "exa", "linkedin", "google"],
|
|
158
|
+
budget: { queries: 4, reads: 6, rounds: 2 },
|
|
159
|
+
};
|
|
160
|
+
const site = {
|
|
161
|
+
id: "raven/site",
|
|
162
|
+
kind: "site",
|
|
163
|
+
version: 1,
|
|
164
|
+
propose: `You plan searches inside one website for one research ask. Every query runs on {site} only.
|
|
165
|
+
|
|
166
|
+
${SHAPE_QUERIES}
|
|
167
|
+
|
|
168
|
+
Rules:
|
|
169
|
+
- At most {n} queries, each 2 to 8 words, as a person types into the site's own search box.
|
|
170
|
+
- Each query reaches a different part of the site: its product or service pages, its pricing, its blog or help, its people.
|
|
171
|
+
- "why" says in one short line what the query would add that is not known yet.
|
|
172
|
+
- No site: operators: the site is set for you.
|
|
173
|
+
|
|
174
|
+
${CONTEXT}`,
|
|
175
|
+
triage: `You decide which pages of {site} to read for one research ask. A read costs time; a skip costs nothing.
|
|
176
|
+
|
|
177
|
+
${SHAPE_HITS}
|
|
178
|
+
|
|
179
|
+
Rules:
|
|
180
|
+
${TRIAGE_RULES}
|
|
181
|
+
- Skip a url off {site}.
|
|
182
|
+
|
|
183
|
+
${CONTEXT}
|
|
184
|
+
Hits:
|
|
185
|
+
{hits}`,
|
|
186
|
+
review: REVIEW,
|
|
187
|
+
sources: ["sitemap", "searxng", "fetch"],
|
|
188
|
+
budget: { queries: 4, reads: 8, rounds: 2 },
|
|
189
|
+
};
|
|
190
|
+
const DEFAULTS = { web, video, channel, person, site };
|
|
191
|
+
/** The default plan file for a kind, validated, as a fresh copy. */
|
|
192
|
+
export function defaultPlanFile(kind) {
|
|
193
|
+
return PlanFileShape.parse(structuredClone(DEFAULTS[kind]));
|
|
194
|
+
}
|
|
195
|
+
export const PLAN_KINDS = Object.keys(DEFAULTS);
|
|
196
|
+
//# sourceMappingURL=index.js.map
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Text the prompts take: what is known, what yielded, what a hit shows for free. */
|
|
2
|
+
import type { HitView, YieldRow } from "./types.js";
|
|
3
|
+
export declare const lines: (xs: readonly string[], none?: string) => string;
|
|
4
|
+
/** One line per row, the keys it has first: `source=exa channel=... hits=12 reads=4 proposed=9 kept=3`. */
|
|
5
|
+
export declare function renderYield(rows: readonly YieldRow[]): string;
|
|
6
|
+
/** Numbered, one hit per line, only the fields it has. */
|
|
7
|
+
export declare function renderHits(hits: readonly HitView[]): string;
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const lines = (xs, none = "(nothing)") => xs.length ? xs.map((x) => `- ${x}`).join("\n") : none;
|
|
2
|
+
/** One line per row, the keys it has first: `source=exa channel=... hits=12 reads=4 proposed=9 kept=3`. */
|
|
3
|
+
export function renderYield(rows) {
|
|
4
|
+
if (!rows.length)
|
|
5
|
+
return "(no history yet)";
|
|
6
|
+
return rows
|
|
7
|
+
.map((r) => {
|
|
8
|
+
const who = ["by", "source", "channel", "kind"]
|
|
9
|
+
.filter((k) => r[k] !== undefined)
|
|
10
|
+
.map((k) => `${k}=${r[k]}`);
|
|
11
|
+
return `- ${[...who, `hits=${r.hits}`, `reads=${r.reads}`, `proposed=${r.proposed}`, `kept=${r.kept}`].join(" ")}`;
|
|
12
|
+
})
|
|
13
|
+
.join("\n");
|
|
14
|
+
}
|
|
15
|
+
const oneLine = (s, max) => {
|
|
16
|
+
const t = s.replace(/\s+/g, " ").trim();
|
|
17
|
+
return t.length > max ? `${t.slice(0, max - 1)}…` : t;
|
|
18
|
+
};
|
|
19
|
+
/** Numbered, one hit per line, only the fields it has. */
|
|
20
|
+
export function renderHits(hits) {
|
|
21
|
+
return hits
|
|
22
|
+
.map((h, i) => {
|
|
23
|
+
const parts = [h.url];
|
|
24
|
+
if (h.title)
|
|
25
|
+
parts.push(`title: ${oneLine(h.title, 120)}`);
|
|
26
|
+
if (h.channel)
|
|
27
|
+
parts.push(`channel: ${h.channel}`);
|
|
28
|
+
if (h.length !== undefined)
|
|
29
|
+
parts.push(`length: ${Math.round(h.length)}s`);
|
|
30
|
+
if (h.date)
|
|
31
|
+
parts.push(`date: ${h.date}`);
|
|
32
|
+
if (h.sources.length)
|
|
33
|
+
parts.push(`sources: ${h.sources.join(",")}`);
|
|
34
|
+
if (h.snippet)
|
|
35
|
+
parts.push(`snippet: ${oneLine(h.snippet, 240)}`);
|
|
36
|
+
return `${i + 1}. ${parts.join(" | ")}`;
|
|
37
|
+
})
|
|
38
|
+
.join("\n");
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=render.js.map
|
package/dist/review.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* After a round: stop, go again from plan, or back to one step. The round budget is a guard
|
|
3
|
+
* rail, not a stop rule: when it is spent raven stops and says so; before that the model decides
|
|
4
|
+
* and says why. The runner takes the edge; raven never loops.
|
|
5
|
+
*/
|
|
6
|
+
import { type Model } from "./model.js";
|
|
7
|
+
import { type Edge, type PlanFile, type Round } from "./types.js";
|
|
8
|
+
export declare function reviewPrompt(round: Round, planFile: PlanFile): string;
|
|
9
|
+
export declare function review(round: Round, model: Model, options?: {
|
|
10
|
+
planFile?: PlanFile;
|
|
11
|
+
}): Promise<Edge>;
|
package/dist/review.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* After a round: stop, go again from plan, or back to one step. The round budget is a guard
|
|
3
|
+
* rail, not a stop rule: when it is spent raven stops and says so; before that the model decides
|
|
4
|
+
* and says why. The runner takes the edge; raven never loops.
|
|
5
|
+
*/
|
|
6
|
+
import { fill } from "./model.js";
|
|
7
|
+
import { defaultPlanFile } from "./plans/index.js";
|
|
8
|
+
import { lines } from "./render.js";
|
|
9
|
+
import { Step, z } from "./types.js";
|
|
10
|
+
const EdgeAnswer = z.object({
|
|
11
|
+
next: z.enum(["stop", "again", "back"]),
|
|
12
|
+
to: Step.optional(),
|
|
13
|
+
why: z.string(),
|
|
14
|
+
});
|
|
15
|
+
export function reviewPrompt(round, planFile) {
|
|
16
|
+
return fill(planFile.review, {
|
|
17
|
+
ask: round.ask.text,
|
|
18
|
+
round: String(round.round),
|
|
19
|
+
rounds: String(round.budget.rounds),
|
|
20
|
+
hits: String(round.hits),
|
|
21
|
+
reads: String(round.reads),
|
|
22
|
+
proposed: String(round.proposed),
|
|
23
|
+
kept: String(round.kept),
|
|
24
|
+
found: lines(round.found),
|
|
25
|
+
notes: lines(round.notes, "(none)"),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export async function review(round, model, options = {}) {
|
|
29
|
+
if (round.round >= round.budget.rounds) {
|
|
30
|
+
return {
|
|
31
|
+
next: "stop",
|
|
32
|
+
why: `round budget spent (${round.round} of ${round.budget.rounds})`,
|
|
33
|
+
from: "ai",
|
|
34
|
+
by: "raven:budget",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const planFile = options.planFile ?? defaultPlanFile(round.ask.kind);
|
|
38
|
+
const out = await model.ask(reviewPrompt(round, planFile), EdgeAnswer);
|
|
39
|
+
const edge = { next: out.next, why: out.why, from: "ai", by: model.id };
|
|
40
|
+
if (out.next === "back")
|
|
41
|
+
edge.to = out.to ?? "fetch";
|
|
42
|
+
return edge;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=review.js.map
|
package/dist/triage.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The filter before the read: for each hit, read or skip, from what the hit shows for free.
|
|
3
|
+
* Hits dedupe by url and keep every source that returned them. The model picks; the read budget
|
|
4
|
+
* caps it; a hit the model did not name is a skip, written down as one.
|
|
5
|
+
*/
|
|
6
|
+
import { type Model } from "./model.js";
|
|
7
|
+
import { type HitView, type Plan, type PlanFile, type Triage, type YieldRow } from "./types.js";
|
|
8
|
+
/** One hit per url, sources merged, order of first sight. */
|
|
9
|
+
export declare function dedupeHits(hits: readonly HitView[]): HitView[];
|
|
10
|
+
export declare function triagePrompt(hits: readonly HitView[], plan: Plan, planFile: PlanFile, yieldRows: readonly YieldRow[]): string;
|
|
11
|
+
/** Read or skip per hit, with why. Reads over the plan's budget flip to skips, in the model's order. */
|
|
12
|
+
export declare function triage(hits: readonly HitView[], plan: Plan, model: Model, options?: {
|
|
13
|
+
planFile?: PlanFile;
|
|
14
|
+
yieldRows?: readonly YieldRow[];
|
|
15
|
+
}): Promise<Triage[]>;
|
package/dist/triage.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The filter before the read: for each hit, read or skip, from what the hit shows for free.
|
|
3
|
+
* Hits dedupe by url and keep every source that returned them. The model picks; the read budget
|
|
4
|
+
* caps it; a hit the model did not name is a skip, written down as one.
|
|
5
|
+
*/
|
|
6
|
+
import { fill } from "./model.js";
|
|
7
|
+
import { defaultPlanFile } from "./plans/index.js";
|
|
8
|
+
import { lines, renderHits, renderYield } from "./render.js";
|
|
9
|
+
import { z } from "./types.js";
|
|
10
|
+
const TriageAnswer = z.object({
|
|
11
|
+
hits: z.array(z.object({ url: z.string(), read: z.boolean(), why: z.string() })),
|
|
12
|
+
});
|
|
13
|
+
/** One hit per url, sources merged, order of first sight. */
|
|
14
|
+
export function dedupeHits(hits) {
|
|
15
|
+
const byUrl = new Map();
|
|
16
|
+
for (const h of hits) {
|
|
17
|
+
const url = h.url.trim();
|
|
18
|
+
const have = byUrl.get(url);
|
|
19
|
+
if (!have) {
|
|
20
|
+
byUrl.set(url, { ...h, url, sources: [...new Set(h.sources)] });
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
for (const s of h.sources)
|
|
24
|
+
if (!have.sources.includes(s))
|
|
25
|
+
have.sources.push(s);
|
|
26
|
+
for (const k of ["title", "channel", "length", "date", "snippet"]) {
|
|
27
|
+
if (have[k] === undefined && h[k] !== undefined)
|
|
28
|
+
have[k] = h[k];
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return [...byUrl.values()];
|
|
32
|
+
}
|
|
33
|
+
export function triagePrompt(hits, plan, planFile, yieldRows) {
|
|
34
|
+
return fill(planFile.triage, {
|
|
35
|
+
n: String(plan.budget.reads),
|
|
36
|
+
ask: plan.ask.text,
|
|
37
|
+
site: plan.ask.site ?? "",
|
|
38
|
+
known: lines(plan.ask.known),
|
|
39
|
+
yield: renderYield(yieldRows),
|
|
40
|
+
hits: renderHits(hits),
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** Read or skip per hit, with why. Reads over the plan's budget flip to skips, in the model's order. */
|
|
44
|
+
export async function triage(hits, plan, model, options = {}) {
|
|
45
|
+
const unique = dedupeHits(hits);
|
|
46
|
+
if (!unique.length)
|
|
47
|
+
return [];
|
|
48
|
+
const planFile = options.planFile ?? defaultPlanFile(plan.ask.kind);
|
|
49
|
+
const out = await model.ask(triagePrompt(unique, plan, planFile, options.yieldRows ?? []), TriageAnswer);
|
|
50
|
+
const said = new Map(out.hits.map((h) => [h.url.trim(), h]));
|
|
51
|
+
let reads = 0;
|
|
52
|
+
return unique.map((h) => {
|
|
53
|
+
const a = said.get(h.url);
|
|
54
|
+
const base = { url: h.url, from: "ai", by: model.id };
|
|
55
|
+
if (!a)
|
|
56
|
+
return { ...base, read: false, why: "not named by the model" };
|
|
57
|
+
if (!a.read)
|
|
58
|
+
return { ...base, read: false, why: a.why };
|
|
59
|
+
if (reads >= plan.budget.reads)
|
|
60
|
+
return { ...base, read: false, why: `over the read budget (${plan.budget.reads})` };
|
|
61
|
+
reads++;
|
|
62
|
+
return { ...base, read: true, why: a.why };
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=triage.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shapes raven owns. A query says what to look for and who asked for it; a plan is the
|
|
3
|
+
* queries of one round plus the sources and budget it runs under; a plan file is the tuned
|
|
4
|
+
* recipe per ask kind. Hits are weaver's; raven sees them through `HitView`, the fields a
|
|
5
|
+
* source shows for free, because weaver depends on raven and not the reverse.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
export declare const AskKind: z.ZodEnum<{
|
|
9
|
+
web: "web";
|
|
10
|
+
video: "video";
|
|
11
|
+
channel: "channel";
|
|
12
|
+
person: "person";
|
|
13
|
+
site: "site";
|
|
14
|
+
}>;
|
|
15
|
+
export type AskKind = z.infer<typeof AskKind>;
|
|
16
|
+
/** Who wrote a record: a model, a plan file or a person. */
|
|
17
|
+
export declare const From: z.ZodEnum<{
|
|
18
|
+
ai: "ai";
|
|
19
|
+
human: "human";
|
|
20
|
+
}>;
|
|
21
|
+
export type From = z.infer<typeof From>;
|
|
22
|
+
/** What someone wants to know, and what is known already. */
|
|
23
|
+
export declare const Ask: z.ZodObject<{
|
|
24
|
+
text: z.ZodString;
|
|
25
|
+
kind: z.ZodEnum<{
|
|
26
|
+
web: "web";
|
|
27
|
+
video: "video";
|
|
28
|
+
channel: "channel";
|
|
29
|
+
person: "person";
|
|
30
|
+
site: "site";
|
|
31
|
+
}>;
|
|
32
|
+
known: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
33
|
+
site: z.ZodOptional<z.ZodString>;
|
|
34
|
+
}, z.core.$strip>;
|
|
35
|
+
export type Ask = z.infer<typeof Ask>;
|
|
36
|
+
/** One thing to look for. `terms` is what a person would type; a source adapter forms its own call from it. */
|
|
37
|
+
export declare const Query: z.ZodObject<{
|
|
38
|
+
kind: z.ZodEnum<{
|
|
39
|
+
web: "web";
|
|
40
|
+
video: "video";
|
|
41
|
+
channel: "channel";
|
|
42
|
+
person: "person";
|
|
43
|
+
site: "site";
|
|
44
|
+
}>;
|
|
45
|
+
terms: z.ZodString;
|
|
46
|
+
site: z.ZodOptional<z.ZodString>;
|
|
47
|
+
why: z.ZodString;
|
|
48
|
+
from: z.ZodEnum<{
|
|
49
|
+
ai: "ai";
|
|
50
|
+
human: "human";
|
|
51
|
+
}>;
|
|
52
|
+
by: z.ZodString;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
export type Query = z.infer<typeof Query>;
|
|
55
|
+
/** Queries from one proposer. The model is one; a plan file, a teammate or a second model are others. */
|
|
56
|
+
export declare const Proposal: z.ZodObject<{
|
|
57
|
+
from: z.ZodEnum<{
|
|
58
|
+
ai: "ai";
|
|
59
|
+
human: "human";
|
|
60
|
+
}>;
|
|
61
|
+
by: z.ZodString;
|
|
62
|
+
queries: z.ZodArray<z.ZodObject<{
|
|
63
|
+
site: z.ZodOptional<z.ZodString>;
|
|
64
|
+
kind: z.ZodEnum<{
|
|
65
|
+
web: "web";
|
|
66
|
+
video: "video";
|
|
67
|
+
channel: "channel";
|
|
68
|
+
person: "person";
|
|
69
|
+
site: "site";
|
|
70
|
+
}>;
|
|
71
|
+
terms: z.ZodString;
|
|
72
|
+
why: z.ZodString;
|
|
73
|
+
}, z.core.$strip>>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
export type Proposal = z.infer<typeof Proposal>;
|
|
76
|
+
export declare const Budget: z.ZodObject<{
|
|
77
|
+
queries: z.ZodNumber;
|
|
78
|
+
reads: z.ZodNumber;
|
|
79
|
+
rounds: z.ZodNumber;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
export type Budget = z.infer<typeof Budget>;
|
|
82
|
+
/**
|
|
83
|
+
* The recipe for one ask kind: the prompts, the sources it may use, the budget. Versioned and
|
|
84
|
+
* tuned like an SOP, stored beside the ledger. `{name}` marks in a prompt are filled from the
|
|
85
|
+
* ask: `{ask}`, `{known}`, `{yield}`, `{n}`, `{year}`, `{site}`.
|
|
86
|
+
*/
|
|
87
|
+
export declare const PlanFile: z.ZodObject<{
|
|
88
|
+
id: z.ZodString;
|
|
89
|
+
kind: z.ZodEnum<{
|
|
90
|
+
web: "web";
|
|
91
|
+
video: "video";
|
|
92
|
+
channel: "channel";
|
|
93
|
+
person: "person";
|
|
94
|
+
site: "site";
|
|
95
|
+
}>;
|
|
96
|
+
version: z.ZodNumber;
|
|
97
|
+
propose: z.ZodString;
|
|
98
|
+
triage: z.ZodString;
|
|
99
|
+
review: z.ZodString;
|
|
100
|
+
sources: z.ZodArray<z.ZodString>;
|
|
101
|
+
budget: z.ZodObject<{
|
|
102
|
+
queries: z.ZodNumber;
|
|
103
|
+
reads: z.ZodNumber;
|
|
104
|
+
rounds: z.ZodNumber;
|
|
105
|
+
}, z.core.$strip>;
|
|
106
|
+
}, z.core.$strip>;
|
|
107
|
+
export type PlanFile = z.infer<typeof PlanFile>;
|
|
108
|
+
/** What a source, channel or proposer yielded before. Raven reads it; wren or the files ledger writes it. */
|
|
109
|
+
export declare const YieldRow: z.ZodObject<{
|
|
110
|
+
by: z.ZodOptional<z.ZodString>;
|
|
111
|
+
source: z.ZodOptional<z.ZodString>;
|
|
112
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
113
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
114
|
+
web: "web";
|
|
115
|
+
video: "video";
|
|
116
|
+
channel: "channel";
|
|
117
|
+
person: "person";
|
|
118
|
+
site: "site";
|
|
119
|
+
}>>;
|
|
120
|
+
hits: z.ZodNumber;
|
|
121
|
+
reads: z.ZodNumber;
|
|
122
|
+
proposed: z.ZodNumber;
|
|
123
|
+
kept: z.ZodNumber;
|
|
124
|
+
}, z.core.$strip>;
|
|
125
|
+
export type YieldRow = z.infer<typeof YieldRow>;
|
|
126
|
+
/** What raven was given for one round: the RL state, kept with the plan. */
|
|
127
|
+
export declare const Snapshot: z.ZodObject<{
|
|
128
|
+
at: z.ZodString;
|
|
129
|
+
known: z.ZodArray<z.ZodString>;
|
|
130
|
+
planFile: z.ZodObject<{
|
|
131
|
+
id: z.ZodString;
|
|
132
|
+
version: z.ZodNumber;
|
|
133
|
+
}, z.core.$strip>;
|
|
134
|
+
model: z.ZodNullable<z.ZodString>;
|
|
135
|
+
yieldRows: z.ZodNumber;
|
|
136
|
+
}, z.core.$strip>;
|
|
137
|
+
export type Snapshot = z.infer<typeof Snapshot>;
|
|
138
|
+
export declare const Plan: z.ZodObject<{
|
|
139
|
+
ask: z.ZodObject<{
|
|
140
|
+
text: z.ZodString;
|
|
141
|
+
kind: z.ZodEnum<{
|
|
142
|
+
web: "web";
|
|
143
|
+
video: "video";
|
|
144
|
+
channel: "channel";
|
|
145
|
+
person: "person";
|
|
146
|
+
site: "site";
|
|
147
|
+
}>;
|
|
148
|
+
known: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
149
|
+
site: z.ZodOptional<z.ZodString>;
|
|
150
|
+
}, z.core.$strip>;
|
|
151
|
+
round: z.ZodNumber;
|
|
152
|
+
queries: z.ZodArray<z.ZodObject<{
|
|
153
|
+
kind: z.ZodEnum<{
|
|
154
|
+
web: "web";
|
|
155
|
+
video: "video";
|
|
156
|
+
channel: "channel";
|
|
157
|
+
person: "person";
|
|
158
|
+
site: "site";
|
|
159
|
+
}>;
|
|
160
|
+
terms: z.ZodString;
|
|
161
|
+
site: z.ZodOptional<z.ZodString>;
|
|
162
|
+
why: z.ZodString;
|
|
163
|
+
from: z.ZodEnum<{
|
|
164
|
+
ai: "ai";
|
|
165
|
+
human: "human";
|
|
166
|
+
}>;
|
|
167
|
+
by: z.ZodString;
|
|
168
|
+
}, z.core.$strip>>;
|
|
169
|
+
sources: z.ZodArray<z.ZodString>;
|
|
170
|
+
budget: z.ZodObject<{
|
|
171
|
+
queries: z.ZodNumber;
|
|
172
|
+
reads: z.ZodNumber;
|
|
173
|
+
rounds: z.ZodNumber;
|
|
174
|
+
}, z.core.$strip>;
|
|
175
|
+
snapshot: z.ZodObject<{
|
|
176
|
+
at: z.ZodString;
|
|
177
|
+
known: z.ZodArray<z.ZodString>;
|
|
178
|
+
planFile: z.ZodObject<{
|
|
179
|
+
id: z.ZodString;
|
|
180
|
+
version: z.ZodNumber;
|
|
181
|
+
}, z.core.$strip>;
|
|
182
|
+
model: z.ZodNullable<z.ZodString>;
|
|
183
|
+
yieldRows: z.ZodNumber;
|
|
184
|
+
}, z.core.$strip>;
|
|
185
|
+
}, z.core.$strip>;
|
|
186
|
+
export type Plan = z.infer<typeof Plan>;
|
|
187
|
+
/** A hit as a source shows it for free: no read has happened. `sources` is every source that returned it. */
|
|
188
|
+
export declare const HitView: z.ZodObject<{
|
|
189
|
+
url: z.ZodString;
|
|
190
|
+
title: z.ZodOptional<z.ZodString>;
|
|
191
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
192
|
+
length: z.ZodOptional<z.ZodNumber>;
|
|
193
|
+
date: z.ZodOptional<z.ZodString>;
|
|
194
|
+
snippet: z.ZodOptional<z.ZodString>;
|
|
195
|
+
sources: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
196
|
+
}, z.core.$strip>;
|
|
197
|
+
export type HitView = z.infer<typeof HitView>;
|
|
198
|
+
export declare const Triage: z.ZodObject<{
|
|
199
|
+
url: z.ZodString;
|
|
200
|
+
read: z.ZodBoolean;
|
|
201
|
+
why: z.ZodString;
|
|
202
|
+
from: z.ZodEnum<{
|
|
203
|
+
ai: "ai";
|
|
204
|
+
human: "human";
|
|
205
|
+
}>;
|
|
206
|
+
by: z.ZodString;
|
|
207
|
+
}, z.core.$strip>;
|
|
208
|
+
export type Triage = z.infer<typeof Triage>;
|
|
209
|
+
/** What one round came to, as counts and notes. The runner fills it; raven reads it. */
|
|
210
|
+
export declare const Round: z.ZodObject<{
|
|
211
|
+
ask: z.ZodObject<{
|
|
212
|
+
text: z.ZodString;
|
|
213
|
+
kind: z.ZodEnum<{
|
|
214
|
+
web: "web";
|
|
215
|
+
video: "video";
|
|
216
|
+
channel: "channel";
|
|
217
|
+
person: "person";
|
|
218
|
+
site: "site";
|
|
219
|
+
}>;
|
|
220
|
+
known: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
221
|
+
site: z.ZodOptional<z.ZodString>;
|
|
222
|
+
}, z.core.$strip>;
|
|
223
|
+
round: z.ZodNumber;
|
|
224
|
+
budget: z.ZodObject<{
|
|
225
|
+
queries: z.ZodNumber;
|
|
226
|
+
reads: z.ZodNumber;
|
|
227
|
+
rounds: z.ZodNumber;
|
|
228
|
+
}, z.core.$strip>;
|
|
229
|
+
hits: z.ZodNumber;
|
|
230
|
+
reads: z.ZodNumber;
|
|
231
|
+
proposed: z.ZodNumber;
|
|
232
|
+
kept: z.ZodNumber;
|
|
233
|
+
found: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
234
|
+
notes: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
235
|
+
}, z.core.$strip>;
|
|
236
|
+
export type Round = z.infer<typeof Round>;
|
|
237
|
+
export declare const Step: z.ZodEnum<{
|
|
238
|
+
read: "read";
|
|
239
|
+
plan: "plan";
|
|
240
|
+
fetch: "fetch";
|
|
241
|
+
extract: "extract";
|
|
242
|
+
}>;
|
|
243
|
+
export type Step = z.infer<typeof Step>;
|
|
244
|
+
/** The edge out of a round. `again` is a new round from `plan`; `back` reruns one step of this round. */
|
|
245
|
+
export declare const Edge: z.ZodObject<{
|
|
246
|
+
next: z.ZodEnum<{
|
|
247
|
+
stop: "stop";
|
|
248
|
+
again: "again";
|
|
249
|
+
back: "back";
|
|
250
|
+
}>;
|
|
251
|
+
to: z.ZodOptional<z.ZodEnum<{
|
|
252
|
+
read: "read";
|
|
253
|
+
plan: "plan";
|
|
254
|
+
fetch: "fetch";
|
|
255
|
+
extract: "extract";
|
|
256
|
+
}>>;
|
|
257
|
+
why: z.ZodString;
|
|
258
|
+
from: z.ZodEnum<{
|
|
259
|
+
ai: "ai";
|
|
260
|
+
human: "human";
|
|
261
|
+
}>;
|
|
262
|
+
by: z.ZodString;
|
|
263
|
+
}, z.core.$strip>;
|
|
264
|
+
export type Edge = z.infer<typeof Edge>;
|
|
265
|
+
export { z };
|