lyrenth-sdk 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 +77 -0
- package/dist/ai.d.ts +34 -0
- package/dist/ai.js +50 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +80 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# lyrenth-sdk (TypeScript / JavaScript)
|
|
2
|
+
|
|
3
|
+
Read the web as clean **AIDocuments** through [Lyrenth](https://lyrenth.com),
|
|
4
|
+
with a ready-made **Vercel AI SDK** tool.
|
|
5
|
+
|
|
6
|
+
Each URL resolves to a stable AIDocument: cleaned Markdown plus title,
|
|
7
|
+
description, and structure, with navigation and boilerplate stripped. Reads go
|
|
8
|
+
through Lyrenth's cross-caller cache, and for verified domains you get the
|
|
9
|
+
publisher's canonical version.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install lyrenth-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Get a free API key at <https://lyrenth.com/signup> and set `LYRENTH_API_KEY`.
|
|
18
|
+
The core client has no dependencies (uses the platform `fetch`); the AI-SDK tool
|
|
19
|
+
uses your existing `ai` and `zod`.
|
|
20
|
+
|
|
21
|
+
## Client
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { Lyrenth } from "lyrenth-sdk";
|
|
25
|
+
|
|
26
|
+
const lyrenth = new Lyrenth(); // reads LYRENTH_API_KEY from the environment
|
|
27
|
+
const doc = await lyrenth.read("https://example.com/article");
|
|
28
|
+
|
|
29
|
+
console.log(doc.title);
|
|
30
|
+
console.log(doc.markdown); // cleaned, agent-ready body
|
|
31
|
+
console.log(doc.wordCount);
|
|
32
|
+
console.log(doc.raw); // full v2 envelope (structure, economics, ...)
|
|
33
|
+
|
|
34
|
+
// just the text:
|
|
35
|
+
const text = await lyrenth.readMarkdown("https://example.com/article");
|
|
36
|
+
|
|
37
|
+
// force a fresh fetch instead of the cached copy:
|
|
38
|
+
const fresh = await lyrenth.read("https://example.com/article", { fresh: true });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Vercel AI SDK tool
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { generateText } from "ai";
|
|
45
|
+
import { lyrenthReadTool } from "lyrenth-sdk/ai";
|
|
46
|
+
|
|
47
|
+
const { text } = await generateText({
|
|
48
|
+
model: yourModel,
|
|
49
|
+
tools: { read_url: lyrenthReadTool() },
|
|
50
|
+
prompt: "Read https://example.com/article and summarize it.",
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The model can now call `read_url` to fetch any page as clean text instead of
|
|
55
|
+
raw HTML. Pass your own configured client with `lyrenthReadTool(new Lyrenth({ apiKey }))`.
|
|
56
|
+
|
|
57
|
+
Targets Vercel AI SDK **v3 / v4** (v5 renamed the tool schema field). The core
|
|
58
|
+
`Lyrenth` client works with any version, wire it into a tool by hand if you are
|
|
59
|
+
on v5.
|
|
60
|
+
|
|
61
|
+
## Why read through Lyrenth
|
|
62
|
+
|
|
63
|
+
- **Cleaner, cheaper.** One stable shape per URL, far fewer tokens than raw HTML.
|
|
64
|
+
- **Cached across callers.** Repeat URLs collapse to a minimal number of origin
|
|
65
|
+
fetches, so it is fast and origin-friendly.
|
|
66
|
+
- **Canonical when verified.** When a site's owner has verified with Lyrenth,
|
|
67
|
+
you get the version they authored, kept fresh by their change signal.
|
|
68
|
+
|
|
69
|
+
## Config
|
|
70
|
+
|
|
71
|
+
| Option / env | Default | Notes |
|
|
72
|
+
|--------------|---------|-------|
|
|
73
|
+
| `apiKey` / `LYRENTH_API_KEY` | none | Free key at <https://lyrenth.com/signup> |
|
|
74
|
+
| `baseUrl` | `https://api.lyrenth.com` | Override for staging / self-host |
|
|
75
|
+
|
|
76
|
+
The AIDocument format is an open contract; see
|
|
77
|
+
<https://lyrenth.com/llms-full.txt>. MIT licensed.
|
package/dist/ai.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Lyrenth } from "./index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Build a Vercel AI SDK tool that reads a URL into a clean AIDocument.
|
|
5
|
+
* Pass your own configured `Lyrenth` client, or omit it to construct one from
|
|
6
|
+
* the `LYRENTH_API_KEY` environment variable.
|
|
7
|
+
*/
|
|
8
|
+
export declare function lyrenthReadTool(client?: Lyrenth): import("ai").Tool<z.ZodObject<{
|
|
9
|
+
url: z.ZodString;
|
|
10
|
+
fresh: z.ZodOptional<z.ZodBoolean>;
|
|
11
|
+
}, "strip", z.ZodTypeAny, {
|
|
12
|
+
url: string;
|
|
13
|
+
fresh?: boolean | undefined;
|
|
14
|
+
}, {
|
|
15
|
+
url: string;
|
|
16
|
+
fresh?: boolean | undefined;
|
|
17
|
+
}>, {
|
|
18
|
+
url: string;
|
|
19
|
+
title: string;
|
|
20
|
+
description: string;
|
|
21
|
+
markdown: string;
|
|
22
|
+
wordCount: number;
|
|
23
|
+
}> & {
|
|
24
|
+
execute: (args: {
|
|
25
|
+
url: string;
|
|
26
|
+
fresh?: boolean | undefined;
|
|
27
|
+
}, options: import("ai").ToolExecutionOptions) => PromiseLike<{
|
|
28
|
+
url: string;
|
|
29
|
+
title: string;
|
|
30
|
+
description: string;
|
|
31
|
+
markdown: string;
|
|
32
|
+
wordCount: number;
|
|
33
|
+
}>;
|
|
34
|
+
};
|
package/dist/ai.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel AI SDK tool backed by Lyrenth (subpath export: "lyrenth-sdk/ai").
|
|
3
|
+
*
|
|
4
|
+
* import { generateText } from "ai";
|
|
5
|
+
* import { lyrenthReadTool } from "lyrenth-sdk/ai";
|
|
6
|
+
*
|
|
7
|
+
* const { text } = await generateText({
|
|
8
|
+
* model: yourModel,
|
|
9
|
+
* tools: { read_url: lyrenthReadTool() },
|
|
10
|
+
* prompt: "Read https://example.com/article and summarize it.",
|
|
11
|
+
* });
|
|
12
|
+
*
|
|
13
|
+
* Requires the `ai` (Vercel AI SDK v3 or v4) and `zod` peer dependencies. v5
|
|
14
|
+
* renamed the tool schema field, so this targets v3/v4; the core `Lyrenth`
|
|
15
|
+
* client in "lyrenth-sdk" works with any version (wire it in by hand).
|
|
16
|
+
*/
|
|
17
|
+
import { tool } from "ai";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
import { Lyrenth } from "./index.js";
|
|
20
|
+
/**
|
|
21
|
+
* Build a Vercel AI SDK tool that reads a URL into a clean AIDocument.
|
|
22
|
+
* Pass your own configured `Lyrenth` client, or omit it to construct one from
|
|
23
|
+
* the `LYRENTH_API_KEY` environment variable.
|
|
24
|
+
*/
|
|
25
|
+
export function lyrenthReadTool(client) {
|
|
26
|
+
const lyrenth = client ?? new Lyrenth();
|
|
27
|
+
return tool({
|
|
28
|
+
description: "Read any public web page as a clean AIDocument: Markdown plus title, " +
|
|
29
|
+
"description, and structure, with navigation and boilerplate stripped. " +
|
|
30
|
+
"Prefer this over a raw HTTP fetch whenever you need the content of a web " +
|
|
31
|
+
"page; it returns far cleaner, lower-token text. Powered by Lyrenth.",
|
|
32
|
+
parameters: z.object({
|
|
33
|
+
url: z.string().url().describe("Absolute http(s) URL of the page to read."),
|
|
34
|
+
fresh: z
|
|
35
|
+
.boolean()
|
|
36
|
+
.optional()
|
|
37
|
+
.describe("Force a fresh fetch instead of the cached version. Default false."),
|
|
38
|
+
}),
|
|
39
|
+
execute: async ({ url, fresh }) => {
|
|
40
|
+
const doc = await lyrenth.read(url, { fresh: fresh ?? false });
|
|
41
|
+
return {
|
|
42
|
+
url: doc.url,
|
|
43
|
+
title: doc.title,
|
|
44
|
+
description: doc.description,
|
|
45
|
+
markdown: doc.markdown,
|
|
46
|
+
wordCount: doc.wordCount,
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lyrenth TypeScript client: read the web as clean AIDocuments.
|
|
3
|
+
*
|
|
4
|
+
* import { Lyrenth } from "lyrenth-sdk";
|
|
5
|
+
*
|
|
6
|
+
* const lyrenth = new Lyrenth(); // reads LYRENTH_API_KEY from env
|
|
7
|
+
* const doc = await lyrenth.read("https://example.com/article");
|
|
8
|
+
* console.log(doc.title, doc.markdown);
|
|
9
|
+
*
|
|
10
|
+
* Free key: https://lyrenth.com/signup. No third-party dependencies (uses the
|
|
11
|
+
* platform `fetch`). The Vercel AI SDK tool lives in the "lyrenth-sdk/ai"
|
|
12
|
+
* subpath export.
|
|
13
|
+
*/
|
|
14
|
+
export interface AIDocument {
|
|
15
|
+
/** Canonical URL of the page (falls back to the requested URL). */
|
|
16
|
+
url: string;
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
/** The cleaned, agent-ready Markdown body. */
|
|
20
|
+
markdown: string;
|
|
21
|
+
wordCount: number;
|
|
22
|
+
/** The full v2 envelope (source, cache, structure, signals, economics). */
|
|
23
|
+
raw: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
export interface LyrenthOptions {
|
|
26
|
+
/** API key (aiwk_...). Falls back to process.env.LYRENTH_API_KEY. */
|
|
27
|
+
apiKey?: string;
|
|
28
|
+
/** API base URL. Defaults to https://api.lyrenth.com. */
|
|
29
|
+
baseUrl?: string;
|
|
30
|
+
}
|
|
31
|
+
export declare class LyrenthError extends Error {
|
|
32
|
+
status?: number;
|
|
33
|
+
constructor(message: string, status?: number);
|
|
34
|
+
}
|
|
35
|
+
export declare class Lyrenth {
|
|
36
|
+
private readonly apiKey;
|
|
37
|
+
private readonly baseUrl;
|
|
38
|
+
constructor(opts?: LyrenthOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a URL into a clean AIDocument via POST /v1/aidocument.
|
|
41
|
+
* Pass `{ fresh: true }` to force a live re-fetch instead of the cached copy.
|
|
42
|
+
*/
|
|
43
|
+
read(url: string, opts?: {
|
|
44
|
+
fresh?: boolean;
|
|
45
|
+
}): Promise<AIDocument>;
|
|
46
|
+
/** Convenience: return just the cleaned Markdown body for a URL. */
|
|
47
|
+
readMarkdown(url: string, opts?: {
|
|
48
|
+
fresh?: boolean;
|
|
49
|
+
}): Promise<string>;
|
|
50
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lyrenth TypeScript client: read the web as clean AIDocuments.
|
|
3
|
+
*
|
|
4
|
+
* import { Lyrenth } from "lyrenth-sdk";
|
|
5
|
+
*
|
|
6
|
+
* const lyrenth = new Lyrenth(); // reads LYRENTH_API_KEY from env
|
|
7
|
+
* const doc = await lyrenth.read("https://example.com/article");
|
|
8
|
+
* console.log(doc.title, doc.markdown);
|
|
9
|
+
*
|
|
10
|
+
* Free key: https://lyrenth.com/signup. No third-party dependencies (uses the
|
|
11
|
+
* platform `fetch`). The Vercel AI SDK tool lives in the "lyrenth-sdk/ai"
|
|
12
|
+
* subpath export.
|
|
13
|
+
*/
|
|
14
|
+
export class LyrenthError extends Error {
|
|
15
|
+
status;
|
|
16
|
+
constructor(message, status) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "LyrenthError";
|
|
19
|
+
this.status = status;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const DEFAULT_BASE_URL = "https://api.lyrenth.com";
|
|
23
|
+
export class Lyrenth {
|
|
24
|
+
apiKey;
|
|
25
|
+
baseUrl;
|
|
26
|
+
constructor(opts = {}) {
|
|
27
|
+
const envKey = typeof process !== "undefined" && process.env
|
|
28
|
+
? process.env.LYRENTH_API_KEY ?? ""
|
|
29
|
+
: "";
|
|
30
|
+
this.apiKey = opts.apiKey ?? envKey;
|
|
31
|
+
this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a URL into a clean AIDocument via POST /v1/aidocument.
|
|
35
|
+
* Pass `{ fresh: true }` to force a live re-fetch instead of the cached copy.
|
|
36
|
+
*/
|
|
37
|
+
async read(url, opts = {}) {
|
|
38
|
+
if (!this.apiKey) {
|
|
39
|
+
throw new LyrenthError("no API key: pass { apiKey } or set LYRENTH_API_KEY (free key at https://lyrenth.com/signup)");
|
|
40
|
+
}
|
|
41
|
+
let res;
|
|
42
|
+
try {
|
|
43
|
+
res = await fetch(`${this.baseUrl}/v1/aidocument`, {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: {
|
|
46
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
url,
|
|
51
|
+
freshness_policy: opts.fresh ? "force_refresh" : "cache_first",
|
|
52
|
+
}),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
throw new LyrenthError(`could not reach Lyrenth: ${e.message}`);
|
|
57
|
+
}
|
|
58
|
+
if (!res.ok) {
|
|
59
|
+
const detail = (await res.text().catch(() => "")).slice(0, 500);
|
|
60
|
+
throw new LyrenthError(`Lyrenth returned HTTP ${res.status}: ${detail}`.trim(), res.status);
|
|
61
|
+
}
|
|
62
|
+
const d = (await res.json());
|
|
63
|
+
const identity = d.identity ?? {};
|
|
64
|
+
const source = d.source ?? {};
|
|
65
|
+
const content = d.content ?? {};
|
|
66
|
+
const signals = d.signals ?? {};
|
|
67
|
+
return {
|
|
68
|
+
url: source.canonical_url || source.url || url,
|
|
69
|
+
title: identity.title ?? "",
|
|
70
|
+
description: identity.description ?? "",
|
|
71
|
+
markdown: content.markdown ?? "",
|
|
72
|
+
wordCount: Number(signals.word_count ?? 0),
|
|
73
|
+
raw: d,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Convenience: return just the cleaned Markdown body for a URL. */
|
|
77
|
+
async readMarkdown(url, opts = {}) {
|
|
78
|
+
return (await this.read(url, opts)).markdown;
|
|
79
|
+
}
|
|
80
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lyrenth-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Read the web as clean AIDocuments through Lyrenth, with a Vercel AI SDK tool.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./ai": {
|
|
15
|
+
"types": "./dist/ai.d.ts",
|
|
16
|
+
"import": "./dist/ai.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"prepare": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=18"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"lyrenth",
|
|
32
|
+
"aidocument",
|
|
33
|
+
"web",
|
|
34
|
+
"reader",
|
|
35
|
+
"agent",
|
|
36
|
+
"rag",
|
|
37
|
+
"llm",
|
|
38
|
+
"vercel",
|
|
39
|
+
"ai-sdk",
|
|
40
|
+
"tool"
|
|
41
|
+
],
|
|
42
|
+
"homepage": "https://lyrenth.com",
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"ai": "^3 || ^4",
|
|
45
|
+
"zod": "^3"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"ai": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"zod": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^20.0.0",
|
|
57
|
+
"ai": "^4.0.0",
|
|
58
|
+
"typescript": "^5.5.0",
|
|
59
|
+
"zod": "^3.23.0"
|
|
60
|
+
}
|
|
61
|
+
}
|