@absolutejs/rag 0.17.0 → 0.18.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/CHANGELOG.md +12 -0
- package/README.md +4 -0
- package/RESEARCH.md +268 -0
- package/changelog.json +262 -235
- package/dist/angular/index.js +174 -2
- package/dist/angular/index.js.map +6 -4
- package/dist/client/index.js +149 -1
- package/dist/client/index.js.map +5 -4
- package/dist/client/research.js +223 -0
- package/dist/client/research.js.map +10 -0
- package/dist/manifest.js +3722 -269
- package/dist/manifest.js.map +29 -3
- package/dist/react/index.js +158 -2
- package/dist/react/index.js.map +6 -4
- package/dist/research/index.js +125286 -0
- package/dist/research/index.js.map +369 -0
- package/dist/src/angular/index.d.ts +1 -0
- package/dist/src/angular/research.service.d.ts +12 -0
- package/dist/src/client/index.d.ts +1 -0
- package/dist/src/client/research.d.ts +30 -0
- package/dist/src/react/index.d.ts +1 -0
- package/dist/src/react/useResearch.d.ts +9 -0
- package/dist/src/research/budget.d.ts +26 -0
- package/dist/src/research/evaluation.d.ts +42 -0
- package/dist/src/research/evidence.d.ts +21 -0
- package/dist/src/research/index.d.ts +9 -0
- package/dist/src/research/manifest.d.ts +18 -0
- package/dist/src/research/plugin.d.ts +230 -0
- package/dist/src/research/runtime.d.ts +2 -0
- package/dist/src/research/schema.d.ts +8 -0
- package/dist/src/research/store.d.ts +29 -0
- package/dist/src/research/types.d.ts +96 -0
- package/dist/src/research/workflows.d.ts +96 -0
- package/dist/src/svelte/createResearch.d.ts +9 -0
- package/dist/src/svelte/index.d.ts +1 -0
- package/dist/src/vue/index.d.ts +1 -0
- package/dist/src/vue/useResearch.d.ts +9 -0
- package/dist/svelte/index.js +164 -2
- package/dist/svelte/index.js.map +6 -4
- package/dist/vue/index.js +164 -2
- package/dist/vue/index.js.map +6 -4
- package/package.json +24 -6
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type DestroyRef } from "@angular/core";
|
|
2
|
+
export declare class ResearchService {
|
|
3
|
+
connect(path?: string, destroyRef?: DestroyRef): {
|
|
4
|
+
state: import("@angular/core").Signal<import("../client").ResearchState>;
|
|
5
|
+
dispose: () => void;
|
|
6
|
+
run: (input: import("../client").ResearchRequest) => Promise<import("../research").ResearchResult>;
|
|
7
|
+
cancel: () => void;
|
|
8
|
+
getSnapshot: () => import("../client").ResearchState;
|
|
9
|
+
subscribe: (listener: () => void) => () => void;
|
|
10
|
+
reset: () => void;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -7,3 +7,4 @@ export { buildRAGMaintenanceOverview, createRAGClient } from "./ragClient";
|
|
|
7
7
|
export type { RAGClient } from "./ragClient";
|
|
8
8
|
export type { RAGClientOptions, RAGDetailedSearchResponse, RAGMaintenanceActionDescriptor, RAGMaintenanceOverview, RAGMaintenancePayload, } from "../../types/client";
|
|
9
9
|
export { buildRAGEvaluationLeaderboard, createRAGEvaluationSuite, runRAGEvaluationSuite, } from "../quality/quality";
|
|
10
|
+
export * from "./research";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ResearchInput, ResearchResult, ResearchProgress } from "../research/types";
|
|
2
|
+
export type ResearchRequest = Pick<ResearchInput, "query" | "task" | "freshness">;
|
|
3
|
+
export type ResearchState = {
|
|
4
|
+
status: "idle" | "running" | "complete" | "cancelled" | "error";
|
|
5
|
+
result: ResearchResult | null;
|
|
6
|
+
progress: ResearchProgress | null;
|
|
7
|
+
error: string | null;
|
|
8
|
+
};
|
|
9
|
+
export type ResearchClientOptions = {
|
|
10
|
+
path?: string;
|
|
11
|
+
fetch?: typeof fetch;
|
|
12
|
+
headers?: () => HeadersInit;
|
|
13
|
+
};
|
|
14
|
+
export declare const createResearchClient: (options?: ResearchClientOptions) => {
|
|
15
|
+
run: (input: ResearchRequest) => Promise<ResearchResult>;
|
|
16
|
+
cancel: () => void;
|
|
17
|
+
getSnapshot: () => ResearchState;
|
|
18
|
+
subscribe: (listener: () => void) => () => void;
|
|
19
|
+
reset: () => void;
|
|
20
|
+
dispose: () => void;
|
|
21
|
+
};
|
|
22
|
+
/** HTML binding uses textContent, never model-produced HTML. Returns cleanup. */
|
|
23
|
+
export declare const bindResearchForm: (form: HTMLFormElement, output: HTMLElement, options?: ResearchClientOptions) => {
|
|
24
|
+
dispose: () => void;
|
|
25
|
+
run: (input: ResearchRequest) => Promise<ResearchResult>;
|
|
26
|
+
cancel: () => void;
|
|
27
|
+
getSnapshot: () => ResearchState;
|
|
28
|
+
subscribe: (listener: () => void) => () => void;
|
|
29
|
+
reset: () => void;
|
|
30
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const useResearch: (path?: string) => {
|
|
2
|
+
state: import("../client").ResearchState;
|
|
3
|
+
run: (input: import("../client").ResearchRequest) => Promise<import("../research").ResearchResult>;
|
|
4
|
+
cancel: () => void;
|
|
5
|
+
getSnapshot: () => import("../client").ResearchState;
|
|
6
|
+
subscribe: (listener: () => void) => () => void;
|
|
7
|
+
reset: () => void;
|
|
8
|
+
dispose: () => void;
|
|
9
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ResearchConfig, ResearchOperation } from "./types";
|
|
2
|
+
type Admission = NonNullable<ResearchConfig["admit"]>;
|
|
3
|
+
type Outcome = Parameters<Exclude<Awaited<ReturnType<Admission>>, false>["settle"]>[0];
|
|
4
|
+
/** Structural adapter for @absolutejs/billing/provider-budget; no second ledger. */
|
|
5
|
+
export type ResearchBudgetConfig = {
|
|
6
|
+
ledger: {
|
|
7
|
+
reserve: (input: {
|
|
8
|
+
id: string;
|
|
9
|
+
scope: string;
|
|
10
|
+
period: string;
|
|
11
|
+
reserveMicros: number;
|
|
12
|
+
maxMicros: number;
|
|
13
|
+
maxRequests: number;
|
|
14
|
+
}) => Promise<boolean>;
|
|
15
|
+
settle: (id: string, status: "fulfilled" | "rejected" | "unknown", actualMicros: number | null) => Promise<void>;
|
|
16
|
+
};
|
|
17
|
+
scope: string;
|
|
18
|
+
period: () => string;
|
|
19
|
+
maxMicros: number;
|
|
20
|
+
maxRequests: number;
|
|
21
|
+
/** Conservative ceilings for configured models, token limits, search and reader. */
|
|
22
|
+
reserveMicros: Record<ResearchOperation, number>;
|
|
23
|
+
actualMicros: (kind: ResearchOperation, outcome: Outcome) => number | null;
|
|
24
|
+
};
|
|
25
|
+
export declare const createResearchBudgetAdmission: (config: ResearchBudgetConfig) => Admission;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { RAGAnswerGroundingEvaluationCase } from "../../types/engine";
|
|
2
|
+
import type { ResearchInput, ResearchResult, ResearchRuntime } from "./types";
|
|
3
|
+
/** Feed research evidence into the existing @absolutejs/rag/quality evaluators. */
|
|
4
|
+
export declare const researchGroundingCase: (id: string, query: string, result: ResearchResult, expectedSources?: string[]) => RAGAnswerGroundingEvaluationCase;
|
|
5
|
+
export type ResearchAcceptance = {
|
|
6
|
+
accepted: number;
|
|
7
|
+
rejected: number;
|
|
8
|
+
reviewMs: number;
|
|
9
|
+
reviewer: string;
|
|
10
|
+
};
|
|
11
|
+
export type ResearchEvaluationCase = {
|
|
12
|
+
id: string;
|
|
13
|
+
input: Pick<ResearchInput, "query" | "task" | "freshness">;
|
|
14
|
+
expectedSources?: string[];
|
|
15
|
+
publishedAfter?: string;
|
|
16
|
+
};
|
|
17
|
+
export declare const evaluateResearch: (options: {
|
|
18
|
+
runtime: ResearchRuntime;
|
|
19
|
+
cases: ResearchEvaluationCase[];
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
/** Supply independent human decisions; absence means unreviewed, never zero errors. */
|
|
22
|
+
review?: (test: ResearchEvaluationCase, result: ResearchResult) => Promise<ResearchAcceptance>;
|
|
23
|
+
/** Total cost must include search, reads, planning, extraction, review and failed attempts. */
|
|
24
|
+
cost?: (result: ResearchResult) => Promise<number | null>;
|
|
25
|
+
}) => Promise<{
|
|
26
|
+
cases: {
|
|
27
|
+
id: string;
|
|
28
|
+
result: ResearchResult<unknown>;
|
|
29
|
+
durationMs: number;
|
|
30
|
+
acceptance: ResearchAcceptance | null;
|
|
31
|
+
costUsd: number | null;
|
|
32
|
+
costPerAcceptedFinding: number | null;
|
|
33
|
+
publicationFreshness: {
|
|
34
|
+
dated: number;
|
|
35
|
+
fresh: number;
|
|
36
|
+
unknown: number;
|
|
37
|
+
} | null;
|
|
38
|
+
groundingCase: RAGAnswerGroundingEvaluationCase;
|
|
39
|
+
}[];
|
|
40
|
+
independentlyReviewed: number;
|
|
41
|
+
totalCostUsd: number | null;
|
|
42
|
+
}>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type SearchSource } from "@absolutejs/search";
|
|
2
|
+
import type { ResearchField } from "./types";
|
|
3
|
+
export declare const ReviewSchema: import("@sinclair/typebox").TObject<{
|
|
4
|
+
fields: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
5
|
+
path: import("@sinclair/typebox").TString;
|
|
6
|
+
verdict: import("@sinclair/typebox").TUnion<import("@sinclair/typebox").TLiteral<"unknown" | "supported" | "unsupported" | "conflicting">[]>;
|
|
7
|
+
citations: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
8
|
+
sourceId: import("@sinclair/typebox").TString;
|
|
9
|
+
quote: import("@sinclair/typebox").TString;
|
|
10
|
+
}>>;
|
|
11
|
+
reason: import("@sinclair/typebox").TString;
|
|
12
|
+
}>>;
|
|
13
|
+
}>;
|
|
14
|
+
export declare const researchLeaves: (value: unknown, maxFields?: number) => Pick<ResearchField, "value" | "path">[];
|
|
15
|
+
/** A model review is fallible. Citation validation proves provenance, not truth. */
|
|
16
|
+
export declare const bindResearchReview: (leaves: ReturnType<typeof researchLeaves>, reviews: {
|
|
17
|
+
path: string;
|
|
18
|
+
verdict: ResearchField["verdict"];
|
|
19
|
+
citations: ResearchField["citations"];
|
|
20
|
+
reason: string;
|
|
21
|
+
}[], sources: SearchSource[]) => ResearchField[];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { createResearch } from "./runtime";
|
|
2
|
+
export { researchPlugin, renderResearchResult, type ResearchPluginOptions, } from "./plugin";
|
|
3
|
+
export { bindResearchReview, researchLeaves } from "./evidence";
|
|
4
|
+
export type * from "./types";
|
|
5
|
+
export * from "./store";
|
|
6
|
+
export * from "./workflows";
|
|
7
|
+
export { researchManifest } from "./manifest";
|
|
8
|
+
export * from "./evaluation";
|
|
9
|
+
export * from "./budget";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ResearchConfig, ResearchRuntime } from "./types";
|
|
2
|
+
export declare const researchManifest: Omit<import("@absolutejs/manifest").PackageManifest<ResearchConfig, ResearchRuntime>, "tools" | "contract" | "settings"> & (({
|
|
3
|
+
contract: 1;
|
|
4
|
+
tools?: Record<string, import("@absolutejs/manifest").LegacyManifestTool<ResearchRuntime>> | undefined;
|
|
5
|
+
} | {
|
|
6
|
+
contract: 2;
|
|
7
|
+
tools?: Record<string, import("@absolutejs/manifest").AuthorizedManifestTool<ResearchRuntime>> | undefined;
|
|
8
|
+
}) & {
|
|
9
|
+
settings: import("@sinclair/typebox").TObject<{
|
|
10
|
+
model: import("@sinclair/typebox").TString;
|
|
11
|
+
limits: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TObject<{
|
|
12
|
+
searches: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
13
|
+
reads: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
14
|
+
rounds: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
15
|
+
timeoutMs: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TInteger>;
|
|
16
|
+
}>>;
|
|
17
|
+
}>;
|
|
18
|
+
});
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import type { ResearchRuntime, ResearchResult } from "./types";
|
|
2
|
+
export declare const renderResearchResult: (result: ResearchResult) => string;
|
|
3
|
+
export type ResearchPluginOptions = {
|
|
4
|
+
runtime: ResearchRuntime | ((request: Request) => ResearchRuntime | Promise<ResearchRuntime>);
|
|
5
|
+
/** Required for all routes, including HTML and streaming. Resolve identity before selecting tenant runtime. */
|
|
6
|
+
authorize: (request: Request) => boolean | Promise<boolean>;
|
|
7
|
+
path?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const researchPlugin: (options: ResearchPluginOptions) => import("elysia/types").AddRoute<"", "local", import("elysia/types").DefaultSingleton, {
|
|
10
|
+
typebox: {};
|
|
11
|
+
error: [];
|
|
12
|
+
}, import("elysia/types").DefaultMetadata, {
|
|
13
|
+
[x: string]: {
|
|
14
|
+
post: {
|
|
15
|
+
body: {
|
|
16
|
+
task?: string | undefined;
|
|
17
|
+
freshness?: string | undefined;
|
|
18
|
+
query: string;
|
|
19
|
+
};
|
|
20
|
+
params: {};
|
|
21
|
+
query: unknown;
|
|
22
|
+
headers: unknown;
|
|
23
|
+
response: {
|
|
24
|
+
200: Response;
|
|
25
|
+
422: {
|
|
26
|
+
type: "validation";
|
|
27
|
+
title: "Validation Error";
|
|
28
|
+
status: 422;
|
|
29
|
+
detail?: string;
|
|
30
|
+
on: string;
|
|
31
|
+
found?: unknown;
|
|
32
|
+
property?: string;
|
|
33
|
+
expected?: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
error: never;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
} & {
|
|
40
|
+
[x: string]: {
|
|
41
|
+
html: {
|
|
42
|
+
post: {
|
|
43
|
+
body: {
|
|
44
|
+
task?: string | undefined;
|
|
45
|
+
freshness?: string | undefined;
|
|
46
|
+
query: string;
|
|
47
|
+
};
|
|
48
|
+
params: {};
|
|
49
|
+
query: unknown;
|
|
50
|
+
headers: unknown;
|
|
51
|
+
response: {
|
|
52
|
+
200: Response;
|
|
53
|
+
422: {
|
|
54
|
+
type: "validation";
|
|
55
|
+
title: "Validation Error";
|
|
56
|
+
status: 422;
|
|
57
|
+
detail?: string;
|
|
58
|
+
on: string;
|
|
59
|
+
found?: unknown;
|
|
60
|
+
property?: string;
|
|
61
|
+
expected?: string;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
error: never;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
}, import("elysia/types").DefaultEphemeral, import("elysia/types").DefaultEphemeral, "post", `${string}/stream`, import("elysia/types").IntersectIfObjectSchema<import("elysia").UnwrapRoute<{
|
|
69
|
+
body: import("typebox").TObject<{
|
|
70
|
+
query: import("typebox").TString;
|
|
71
|
+
task: import("typebox").TOptional<import("typebox").TString>;
|
|
72
|
+
freshness: import("typebox").TOptional<import("typebox").TString>;
|
|
73
|
+
}>;
|
|
74
|
+
}, {}, `/${string}/stream`>, import("elysia/types").MergeScopedSchemas<{}, {}, {}>>, {}, ({ request, body }: {
|
|
75
|
+
body: {
|
|
76
|
+
task?: string | undefined;
|
|
77
|
+
freshness?: string | undefined;
|
|
78
|
+
query: string;
|
|
79
|
+
};
|
|
80
|
+
query: Record<string, string | undefined>;
|
|
81
|
+
params: {};
|
|
82
|
+
headers: Record<string, string | undefined>;
|
|
83
|
+
cookie: Record<string, import("elysia").Cookie<unknown>>;
|
|
84
|
+
server: import("elysia").Server | null;
|
|
85
|
+
redirect: import("elysia").redirect;
|
|
86
|
+
set: {
|
|
87
|
+
headers: import("elysia").HTTPHeaders;
|
|
88
|
+
status?: number | keyof import("elysia").StatusMap;
|
|
89
|
+
cookie?: Record<string, import("elysia").BaseCookie>;
|
|
90
|
+
};
|
|
91
|
+
status: <const Code extends number | keyof import("elysia").StatusMap, const T = Code extends 500 | 100 | 200 | 400 | 404 | 300 | 101 | 102 | 103 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 301 | 302 | 303 | 304 | 307 | 308 | 401 | 402 | 403 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511 ? {
|
|
92
|
+
readonly 100: "Continue";
|
|
93
|
+
readonly 101: "Switching Protocols";
|
|
94
|
+
readonly 102: "Processing";
|
|
95
|
+
readonly 103: "Early Hints";
|
|
96
|
+
readonly 200: "OK";
|
|
97
|
+
readonly 201: "Created";
|
|
98
|
+
readonly 202: "Accepted";
|
|
99
|
+
readonly 203: "Non-Authoritative Information";
|
|
100
|
+
readonly 204: "No Content";
|
|
101
|
+
readonly 205: "Reset Content";
|
|
102
|
+
readonly 206: "Partial Content";
|
|
103
|
+
readonly 207: "Multi-Status";
|
|
104
|
+
readonly 208: "Already Reported";
|
|
105
|
+
readonly 300: "Multiple Choices";
|
|
106
|
+
readonly 301: "Moved Permanently";
|
|
107
|
+
readonly 302: "Found";
|
|
108
|
+
readonly 303: "See Other";
|
|
109
|
+
readonly 304: "Not Modified";
|
|
110
|
+
readonly 307: "Temporary Redirect";
|
|
111
|
+
readonly 308: "Permanent Redirect";
|
|
112
|
+
readonly 400: "Bad Request";
|
|
113
|
+
readonly 401: "Unauthorized";
|
|
114
|
+
readonly 402: "Payment Required";
|
|
115
|
+
readonly 403: "Forbidden";
|
|
116
|
+
readonly 404: "Not Found";
|
|
117
|
+
readonly 405: "Method Not Allowed";
|
|
118
|
+
readonly 406: "Not Acceptable";
|
|
119
|
+
readonly 407: "Proxy Authentication Required";
|
|
120
|
+
readonly 408: "Request Timeout";
|
|
121
|
+
readonly 409: "Conflict";
|
|
122
|
+
readonly 410: "Gone";
|
|
123
|
+
readonly 411: "Length Required";
|
|
124
|
+
readonly 412: "Precondition Failed";
|
|
125
|
+
readonly 413: "Payload Too Large";
|
|
126
|
+
readonly 414: "URI Too Long";
|
|
127
|
+
readonly 415: "Unsupported Media Type";
|
|
128
|
+
readonly 416: "Range Not Satisfiable";
|
|
129
|
+
readonly 417: "Expectation Failed";
|
|
130
|
+
readonly 418: "I'm a teapot";
|
|
131
|
+
readonly 420: "Enhance Your Calm";
|
|
132
|
+
readonly 421: "Misdirected Request";
|
|
133
|
+
readonly 422: "Unprocessable Content";
|
|
134
|
+
readonly 423: "Locked";
|
|
135
|
+
readonly 424: "Failed Dependency";
|
|
136
|
+
readonly 425: "Too Early";
|
|
137
|
+
readonly 426: "Upgrade Required";
|
|
138
|
+
readonly 428: "Precondition Required";
|
|
139
|
+
readonly 429: "Too Many Requests";
|
|
140
|
+
readonly 431: "Request Header Fields Too Large";
|
|
141
|
+
readonly 451: "Unavailable For Legal Reasons";
|
|
142
|
+
readonly 500: "Internal Server Error";
|
|
143
|
+
readonly 501: "Not Implemented";
|
|
144
|
+
readonly 502: "Bad Gateway";
|
|
145
|
+
readonly 503: "Service Unavailable";
|
|
146
|
+
readonly 504: "Gateway Timeout";
|
|
147
|
+
readonly 505: "HTTP Version Not Supported";
|
|
148
|
+
readonly 506: "Variant Also Negotiates";
|
|
149
|
+
readonly 507: "Insufficient Storage";
|
|
150
|
+
readonly 508: "Loop Detected";
|
|
151
|
+
readonly 510: "Not Extended";
|
|
152
|
+
readonly 511: "Network Authentication Required";
|
|
153
|
+
}[Code] : Code>(code: Code, response?: T) => import("elysia").ElysiaStatus<Code, T, Code extends "Continue" | "Switching Protocols" | "Processing" | "Early Hints" | "OK" | "Created" | "Accepted" | "Non-Authoritative Information" | "No Content" | "Reset Content" | "Partial Content" | "Multi-Status" | "Already Reported" | "Multiple Choices" | "Moved Permanently" | "Found" | "See Other" | "Not Modified" | "Temporary Redirect" | "Permanent Redirect" | "Bad Request" | "Unauthorized" | "Payment Required" | "Forbidden" | "Not Found" | "Method Not Allowed" | "Not Acceptable" | "Proxy Authentication Required" | "Request Timeout" | "Conflict" | "Gone" | "Length Required" | "Precondition Failed" | "Payload Too Large" | "URI Too Long" | "Unsupported Media Type" | "Range Not Satisfiable" | "Expectation Failed" | "I'm a teapot" | "Enhance Your Calm" | "Misdirected Request" | "Unprocessable Content" | "Locked" | "Failed Dependency" | "Too Early" | "Upgrade Required" | "Precondition Required" | "Too Many Requests" | "Request Header Fields Too Large" | "Unavailable For Legal Reasons" | "Internal Server Error" | "Not Implemented" | "Bad Gateway" | "Service Unavailable" | "Gateway Timeout" | "HTTP Version Not Supported" | "Variant Also Negotiates" | "Insufficient Storage" | "Loop Detected" | "Not Extended" | "Network Authentication Required" ? {
|
|
154
|
+
readonly Continue: 100;
|
|
155
|
+
readonly "Switching Protocols": 101;
|
|
156
|
+
readonly Processing: 102;
|
|
157
|
+
readonly "Early Hints": 103;
|
|
158
|
+
readonly OK: 200;
|
|
159
|
+
readonly Created: 201;
|
|
160
|
+
readonly Accepted: 202;
|
|
161
|
+
readonly "Non-Authoritative Information": 203;
|
|
162
|
+
readonly "No Content": 204;
|
|
163
|
+
readonly "Reset Content": 205;
|
|
164
|
+
readonly "Partial Content": 206;
|
|
165
|
+
readonly "Multi-Status": 207;
|
|
166
|
+
readonly "Already Reported": 208;
|
|
167
|
+
readonly "Multiple Choices": 300;
|
|
168
|
+
readonly "Moved Permanently": 301;
|
|
169
|
+
readonly Found: 302;
|
|
170
|
+
readonly "See Other": 303;
|
|
171
|
+
readonly "Not Modified": 304;
|
|
172
|
+
readonly "Temporary Redirect": 307;
|
|
173
|
+
readonly "Permanent Redirect": 308;
|
|
174
|
+
readonly "Bad Request": 400;
|
|
175
|
+
readonly Unauthorized: 401;
|
|
176
|
+
readonly "Payment Required": 402;
|
|
177
|
+
readonly Forbidden: 403;
|
|
178
|
+
readonly "Not Found": 404;
|
|
179
|
+
readonly "Method Not Allowed": 405;
|
|
180
|
+
readonly "Not Acceptable": 406;
|
|
181
|
+
readonly "Proxy Authentication Required": 407;
|
|
182
|
+
readonly "Request Timeout": 408;
|
|
183
|
+
readonly Conflict: 409;
|
|
184
|
+
readonly Gone: 410;
|
|
185
|
+
readonly "Length Required": 411;
|
|
186
|
+
readonly "Precondition Failed": 412;
|
|
187
|
+
readonly "Payload Too Large": 413;
|
|
188
|
+
readonly "URI Too Long": 414;
|
|
189
|
+
readonly "Unsupported Media Type": 415;
|
|
190
|
+
readonly "Range Not Satisfiable": 416;
|
|
191
|
+
readonly "Expectation Failed": 417;
|
|
192
|
+
readonly "I'm a teapot": 418;
|
|
193
|
+
readonly "Enhance Your Calm": 420;
|
|
194
|
+
readonly "Misdirected Request": 421;
|
|
195
|
+
readonly "Unprocessable Content": 422;
|
|
196
|
+
readonly Locked: 423;
|
|
197
|
+
readonly "Failed Dependency": 424;
|
|
198
|
+
readonly "Too Early": 425;
|
|
199
|
+
readonly "Upgrade Required": 426;
|
|
200
|
+
readonly "Precondition Required": 428;
|
|
201
|
+
readonly "Too Many Requests": 429;
|
|
202
|
+
readonly "Request Header Fields Too Large": 431;
|
|
203
|
+
readonly "Unavailable For Legal Reasons": 451;
|
|
204
|
+
readonly "Internal Server Error": 500;
|
|
205
|
+
readonly "Not Implemented": 501;
|
|
206
|
+
readonly "Bad Gateway": 502;
|
|
207
|
+
readonly "Service Unavailable": 503;
|
|
208
|
+
readonly "Gateway Timeout": 504;
|
|
209
|
+
readonly "HTTP Version Not Supported": 505;
|
|
210
|
+
readonly "Variant Also Negotiates": 506;
|
|
211
|
+
readonly "Insufficient Storage": 507;
|
|
212
|
+
readonly "Loop Detected": 508;
|
|
213
|
+
readonly "Not Extended": 510;
|
|
214
|
+
readonly "Network Authentication Required": 511;
|
|
215
|
+
}[Code] : Code>;
|
|
216
|
+
defer: (fn: import("elysia/types").AfterResponseHandler<NoInfer<import("elysia/types").IntersectIfObjectSchema<import("elysia").UnwrapRoute<{
|
|
217
|
+
body: import("typebox").TObject<{
|
|
218
|
+
query: import("typebox").TString;
|
|
219
|
+
task: import("typebox").TOptional<import("typebox").TString>;
|
|
220
|
+
freshness: import("typebox").TOptional<import("typebox").TString>;
|
|
221
|
+
}>;
|
|
222
|
+
}, {}, `/${string}/stream`>, import("elysia/types").MergeScopedSchemas<{}, {}, {}>>>, NoInfer<import("elysia/types").DefaultSingleton & {
|
|
223
|
+
derive: {};
|
|
224
|
+
}>>) => import("elysia/types").MaybePromise<void>;
|
|
225
|
+
readonly path: string;
|
|
226
|
+
route?: string | undefined;
|
|
227
|
+
rid?: string | undefined;
|
|
228
|
+
request: Request;
|
|
229
|
+
store: {};
|
|
230
|
+
}) => Promise<Response>>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type TSchema, type Static as LegacyStatic } from "@sinclair/typebox";
|
|
2
|
+
import type { Static } from "typebox";
|
|
3
|
+
/** JSON-compatible TypeBox 0.34 or TypeBox 1 schemas, including Elysia 2's t. */
|
|
4
|
+
export type ResearchSchema = TSchema | {
|
|
5
|
+
"~kind": string;
|
|
6
|
+
};
|
|
7
|
+
export type ResearchStatic<S extends ResearchSchema> = S extends TSchema ? LegacyStatic<S> : Static<S>;
|
|
8
|
+
export declare const checkResearchValue: <S extends ResearchSchema>(schema: S, value: unknown) => value is ResearchStatic<S>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type ResearchCheckpoint = {
|
|
2
|
+
revision: number;
|
|
3
|
+
value: unknown;
|
|
4
|
+
fingerprint: string;
|
|
5
|
+
};
|
|
6
|
+
export type ResearchClaim = ResearchCheckpoint & {
|
|
7
|
+
token: string;
|
|
8
|
+
};
|
|
9
|
+
export type ResearchDelivery = {
|
|
10
|
+
id: string;
|
|
11
|
+
key: string;
|
|
12
|
+
payload: unknown;
|
|
13
|
+
};
|
|
14
|
+
export type ResearchWorkflowStore = {
|
|
15
|
+
claim: (key: string, fingerprint: string, leaseMs: number) => Promise<ResearchClaim | null>;
|
|
16
|
+
/** Commit state and append delivery records atomically, fenced against lease expiry and takeover. */
|
|
17
|
+
commit: (key: string, claim: ResearchClaim, value: unknown, events?: ResearchDelivery[]) => Promise<boolean>;
|
|
18
|
+
release: (key: string, token: string) => Promise<void>;
|
|
19
|
+
deliveries: (key: string, limit: number) => Promise<ResearchDelivery[]>;
|
|
20
|
+
acknowledge: (key: string, id: string) => Promise<void>;
|
|
21
|
+
};
|
|
22
|
+
export declare const researchKey: (value: unknown) => Promise<string>;
|
|
23
|
+
export declare const createMemoryResearchWorkflowStore: (now?: () => number) => ResearchWorkflowStore;
|
|
24
|
+
export type ResearchSqlClient = {
|
|
25
|
+
unsafe: (query: string, parameters?: unknown[]) => PromiseLike<Record<string, unknown>[]>;
|
|
26
|
+
};
|
|
27
|
+
export declare const researchWorkflowPostgresSchemaSql: () => string;
|
|
28
|
+
/** SQL operations use database time and one fenced statement for state plus outbox. */
|
|
29
|
+
export declare const createPostgresResearchWorkflowStore: (sql: ResearchSqlClient) => ResearchWorkflowStore;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { AIProviderConfig, AIUsage } from "@absolutejs/ai";
|
|
2
|
+
import type { SearchProvider, SearchResult, SearchSource, SearchCacheStore } from "@absolutejs/search";
|
|
3
|
+
import type { ResearchSchema, ResearchStatic } from "./schema";
|
|
4
|
+
export type { ResearchSchema, ResearchStatic } from "./schema";
|
|
5
|
+
import type { ReadWebpageOptions, WebReadResult } from "../web";
|
|
6
|
+
export type ResearchOperation = "search" | "read" | "plan" | "extract" | "review";
|
|
7
|
+
export type ResearchProgress = {
|
|
8
|
+
phase: ResearchOperation | "complete";
|
|
9
|
+
completed: number;
|
|
10
|
+
limit: number;
|
|
11
|
+
};
|
|
12
|
+
export type ResearchField = {
|
|
13
|
+
/** RFC 6901 JSON pointer, including array indices. */
|
|
14
|
+
path: string;
|
|
15
|
+
value: string | number | boolean | null;
|
|
16
|
+
verdict: "supported" | "unsupported" | "conflicting" | "unknown";
|
|
17
|
+
citations: {
|
|
18
|
+
sourceId: string;
|
|
19
|
+
quote: string;
|
|
20
|
+
}[];
|
|
21
|
+
reason: string;
|
|
22
|
+
};
|
|
23
|
+
export type ResearchResult<T = unknown> = {
|
|
24
|
+
id: string;
|
|
25
|
+
status: "reviewed" | "partial" | "empty" | "unavailable";
|
|
26
|
+
/** Only populated when every primitive field passed evidence review. */
|
|
27
|
+
data: T | null;
|
|
28
|
+
fields: ResearchField[];
|
|
29
|
+
sources: SearchSource[];
|
|
30
|
+
searches: SearchResult[];
|
|
31
|
+
limitations: string[];
|
|
32
|
+
generatedAt: string;
|
|
33
|
+
operations: {
|
|
34
|
+
kind: ResearchOperation;
|
|
35
|
+
status: "fulfilled" | "unknown";
|
|
36
|
+
usage?: AIUsage;
|
|
37
|
+
durationMs: number;
|
|
38
|
+
}[];
|
|
39
|
+
};
|
|
40
|
+
export type ResearchTask<S extends ResearchSchema = ResearchSchema> = {
|
|
41
|
+
schema: S;
|
|
42
|
+
instructions?: string;
|
|
43
|
+
};
|
|
44
|
+
export type ResearchInput = {
|
|
45
|
+
queries?: string[];
|
|
46
|
+
requiredPhrases?: string[];
|
|
47
|
+
query: string;
|
|
48
|
+
task?: string;
|
|
49
|
+
freshness?: string;
|
|
50
|
+
signal?: AbortSignal;
|
|
51
|
+
onProgress?: (event: ResearchProgress) => void;
|
|
52
|
+
};
|
|
53
|
+
export type ResearchLimits = {
|
|
54
|
+
searches: number;
|
|
55
|
+
reads: number;
|
|
56
|
+
rounds: number;
|
|
57
|
+
timeoutMs: number;
|
|
58
|
+
evidenceChars: number;
|
|
59
|
+
outputTokens: number;
|
|
60
|
+
fields: number;
|
|
61
|
+
};
|
|
62
|
+
export type ResearchConfig = {
|
|
63
|
+
/** Optional host accounting adapter; defaults to the standard AI generator. */
|
|
64
|
+
generateObject?: typeof import("@absolutejs/ai").generateObjectAI;
|
|
65
|
+
budget?: import("./budget").ResearchBudgetConfig;
|
|
66
|
+
search: SearchProvider;
|
|
67
|
+
provider: AIProviderConfig;
|
|
68
|
+
model: string;
|
|
69
|
+
tasks?: Record<string, ResearchTask>;
|
|
70
|
+
limits?: Partial<ResearchLimits>;
|
|
71
|
+
/** Explicit shared-public or tenant scope. Omit to disable search caching. */
|
|
72
|
+
cache?: {
|
|
73
|
+
scope: string;
|
|
74
|
+
store?: SearchCacheStore;
|
|
75
|
+
ttlMs?: number;
|
|
76
|
+
capacity?: number;
|
|
77
|
+
};
|
|
78
|
+
reader?: (options: ReadWebpageOptions) => Promise<WebReadResult>;
|
|
79
|
+
render?: ReadWebpageOptions["render"];
|
|
80
|
+
/** Called before each operation. May atomically reserve tenant budget or deny. */
|
|
81
|
+
admit?: (operation: {
|
|
82
|
+
runId: string;
|
|
83
|
+
kind: ResearchOperation;
|
|
84
|
+
signal: AbortSignal;
|
|
85
|
+
}) => Promise<false | {
|
|
86
|
+
settle: (outcome: {
|
|
87
|
+
status: "fulfilled" | "unknown";
|
|
88
|
+
usage?: AIUsage;
|
|
89
|
+
search?: SearchResult;
|
|
90
|
+
}) => Promise<void>;
|
|
91
|
+
}>;
|
|
92
|
+
};
|
|
93
|
+
export type ResearchRuntime = {
|
|
94
|
+
run: (input: ResearchInput) => Promise<ResearchResult>;
|
|
95
|
+
extract: <S extends ResearchSchema>(task: ResearchTask<S>, input: ResearchInput) => Promise<ResearchResult<ResearchStatic<S>>>;
|
|
96
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { ResearchResult, ResearchRuntime } from "./types";
|
|
2
|
+
import { type ResearchWorkflowStore, type ResearchDelivery } from "./store";
|
|
3
|
+
export type ResearchCriterion = {
|
|
4
|
+
id: string;
|
|
5
|
+
description: string;
|
|
6
|
+
};
|
|
7
|
+
export type ResearchCandidate = {
|
|
8
|
+
name: string;
|
|
9
|
+
domain: string;
|
|
10
|
+
evidence: ResearchResult;
|
|
11
|
+
criteria: {
|
|
12
|
+
id: string;
|
|
13
|
+
verdict: "matched" | "not_matched" | "unknown";
|
|
14
|
+
evidence: ResearchResult;
|
|
15
|
+
}[];
|
|
16
|
+
};
|
|
17
|
+
export declare const discoverResearchCompanies: (runtime: ResearchRuntime, input: {
|
|
18
|
+
query: string;
|
|
19
|
+
criteria: ResearchCriterion[];
|
|
20
|
+
limit?: number;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}) => Promise<{
|
|
23
|
+
discovery: ResearchResult<{
|
|
24
|
+
companies: {
|
|
25
|
+
name: string;
|
|
26
|
+
domain: string;
|
|
27
|
+
}[];
|
|
28
|
+
}>;
|
|
29
|
+
candidates: ResearchCandidate[];
|
|
30
|
+
accepted: ResearchCandidate[];
|
|
31
|
+
}>;
|
|
32
|
+
export type ResearchBatchItem = {
|
|
33
|
+
id: string;
|
|
34
|
+
query: string;
|
|
35
|
+
task?: string;
|
|
36
|
+
freshness?: string;
|
|
37
|
+
};
|
|
38
|
+
export type ResearchMonitorEvent = {
|
|
39
|
+
id: string;
|
|
40
|
+
occurredAt: string;
|
|
41
|
+
fields: string[];
|
|
42
|
+
payload: unknown;
|
|
43
|
+
};
|
|
44
|
+
export declare const createResearchWorkflows: (options: {
|
|
45
|
+
runtime: ResearchRuntime;
|
|
46
|
+
store: ResearchWorkflowStore;
|
|
47
|
+
scope: string;
|
|
48
|
+
version: string;
|
|
49
|
+
leaseMs?: number;
|
|
50
|
+
now?: () => number;
|
|
51
|
+
}) => {
|
|
52
|
+
batch(input: {
|
|
53
|
+
id: string;
|
|
54
|
+
items: ResearchBatchItem[];
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
id: string;
|
|
58
|
+
status: "complete" | "busy" | "lease_lost";
|
|
59
|
+
result?: ResearchResult;
|
|
60
|
+
}[]>;
|
|
61
|
+
/** Schedule this function using the existing Queue/cron infrastructure. It owns no timer. */
|
|
62
|
+
monitor(input: {
|
|
63
|
+
id: string;
|
|
64
|
+
query: string;
|
|
65
|
+
task?: string;
|
|
66
|
+
freshness?: string;
|
|
67
|
+
signal?: AbortSignal;
|
|
68
|
+
select: (result: ResearchResult) => ResearchMonitorEvent[];
|
|
69
|
+
}): Promise<{
|
|
70
|
+
status: "busy";
|
|
71
|
+
events: number;
|
|
72
|
+
result?: undefined;
|
|
73
|
+
} | {
|
|
74
|
+
status: "incomplete";
|
|
75
|
+
events: number;
|
|
76
|
+
result: ResearchResult<unknown>;
|
|
77
|
+
} | {
|
|
78
|
+
status: "updated" | "baseline" | "lease_lost";
|
|
79
|
+
events: number;
|
|
80
|
+
result: ResearchResult<unknown>;
|
|
81
|
+
}>;
|
|
82
|
+
/** Delivery is at-least-once: the receiver MUST deduplicate using event.id. */
|
|
83
|
+
deliverMonitor(id: string, deliver: (event: ResearchDelivery) => Promise<void>): Promise<number>;
|
|
84
|
+
};
|
|
85
|
+
export declare const researchMonitorTask: {
|
|
86
|
+
schema: import("@sinclair/typebox").TObject<{
|
|
87
|
+
events: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
88
|
+
entity: import("@sinclair/typebox").TString;
|
|
89
|
+
type: import("@sinclair/typebox").TString;
|
|
90
|
+
occurredAt: import("@sinclair/typebox").TString;
|
|
91
|
+
summary: import("@sinclair/typebox").TString;
|
|
92
|
+
}>>;
|
|
93
|
+
}>;
|
|
94
|
+
instructions: string;
|
|
95
|
+
};
|
|
96
|
+
export declare const selectResearchMonitorEvents: (result: ResearchResult) => ResearchMonitorEvent[];
|