@ahtmljs/agent 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/dist/client.d.ts +53 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +142 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/tokens.d.ts +35 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +86 -0
- package/dist/tokens.js.map +1 -0
- package/dist/workflow.d.ts +44 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.js +84 -0
- package/dist/workflow.js.map +1 -0
- package/package.json +34 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AHTMLClient — the agent-side fetcher.
|
|
3
|
+
*
|
|
4
|
+
* Behaviour worth understanding:
|
|
5
|
+
*
|
|
6
|
+
* - Defaults to Accept: application/ahtml+text (compact, token-optimal).
|
|
7
|
+
* - Caches snapshots by URL keyed on ETag.
|
|
8
|
+
* - On second fetch sends If-None-Match; 304 reuses cached body.
|
|
9
|
+
* - Optional diff mode sends ?since=<etag>; reconstructs snapshot via applyDiff.
|
|
10
|
+
* - Respects the site's TTL when deciding to skip the network entirely.
|
|
11
|
+
*
|
|
12
|
+
* No network library — uses the global fetch (Node 20+, modern browsers).
|
|
13
|
+
*/
|
|
14
|
+
import { type Snapshot } from '@ahtmljs/schema';
|
|
15
|
+
export interface FetchOptions {
|
|
16
|
+
/** "compact" (default, token-optimal) or "json". */
|
|
17
|
+
format?: 'compact' | 'json';
|
|
18
|
+
/** Bypass the local cache. */
|
|
19
|
+
noCache?: boolean;
|
|
20
|
+
/** Allow returning a stale-but-cached snapshot if the network fails. */
|
|
21
|
+
allowStale?: boolean;
|
|
22
|
+
/** Identity header. Set this when AHTML providers gate by agent identity. */
|
|
23
|
+
agent?: string;
|
|
24
|
+
/** Auth bearer for action execution endpoints. */
|
|
25
|
+
bearer?: string;
|
|
26
|
+
/** Custom fetch override (testing). */
|
|
27
|
+
fetch?: typeof fetch;
|
|
28
|
+
}
|
|
29
|
+
export interface CachedSnapshot {
|
|
30
|
+
snapshot: Snapshot;
|
|
31
|
+
fetchedAt: number;
|
|
32
|
+
etag?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare class AHTMLClient {
|
|
35
|
+
private defaults;
|
|
36
|
+
private cache;
|
|
37
|
+
constructor(defaults?: FetchOptions);
|
|
38
|
+
/**
|
|
39
|
+
* Fetch the snapshot for a URL. Uses ETag-based incremental fetch by
|
|
40
|
+
* default; falls back to the diff endpoint when the cached snapshot is
|
|
41
|
+
* stale enough that the server might prefer to send a delta.
|
|
42
|
+
*/
|
|
43
|
+
fetch(url: string, opts?: FetchOptions): Promise<Snapshot>;
|
|
44
|
+
private storeFromResponse;
|
|
45
|
+
invalidate(url?: string): void;
|
|
46
|
+
/** Discover a site's manifest. Returns the parsed JSON. */
|
|
47
|
+
manifest(siteOrUrl: string, opts?: FetchOptions): Promise<unknown>;
|
|
48
|
+
}
|
|
49
|
+
export declare class AHTMLError extends Error {
|
|
50
|
+
status: number;
|
|
51
|
+
constructor(status: number, message: string);
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAIL,KAAK,QAAQ,EAEd,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC5B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,WAAW;IAGV,OAAO,CAAC,QAAQ;IAF5B,OAAO,CAAC,KAAK,CAAqC;gBAE9B,QAAQ,GAAE,YAAiB;IAE/C;;;;OAIG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,QAAQ,CAAC;YAsEtD,iBAAiB;IAW/B,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAK9B,2DAA2D;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;CAU7E;AAED,qBAAa,UAAW,SAAQ,KAAK;IAChB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAInD"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AHTMLClient — the agent-side fetcher.
|
|
3
|
+
*
|
|
4
|
+
* Behaviour worth understanding:
|
|
5
|
+
*
|
|
6
|
+
* - Defaults to Accept: application/ahtml+text (compact, token-optimal).
|
|
7
|
+
* - Caches snapshots by URL keyed on ETag.
|
|
8
|
+
* - On second fetch sends If-None-Match; 304 reuses cached body.
|
|
9
|
+
* - Optional diff mode sends ?since=<etag>; reconstructs snapshot via applyDiff.
|
|
10
|
+
* - Respects the site's TTL when deciding to skip the network entirely.
|
|
11
|
+
*
|
|
12
|
+
* No network library — uses the global fetch (Node 20+, modern browsers).
|
|
13
|
+
*/
|
|
14
|
+
import { fromCompact, fromJson, applyDiff, } from '@ahtmljs/schema';
|
|
15
|
+
export class AHTMLClient {
|
|
16
|
+
defaults;
|
|
17
|
+
cache = new Map();
|
|
18
|
+
constructor(defaults = {}) {
|
|
19
|
+
this.defaults = defaults;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Fetch the snapshot for a URL. Uses ETag-based incremental fetch by
|
|
23
|
+
* default; falls back to the diff endpoint when the cached snapshot is
|
|
24
|
+
* stale enough that the server might prefer to send a delta.
|
|
25
|
+
*/
|
|
26
|
+
async fetch(url, opts = {}) {
|
|
27
|
+
const o = { ...this.defaults, ...opts };
|
|
28
|
+
const fetcher = o.fetch ?? globalThis.fetch;
|
|
29
|
+
const cached = this.cache.get(url);
|
|
30
|
+
// 1) Fresh cache (within TTL) — skip the network entirely.
|
|
31
|
+
if (cached && !o.noCache && isFresh(cached)) {
|
|
32
|
+
return cached.snapshot;
|
|
33
|
+
}
|
|
34
|
+
const accept = o.format === 'json'
|
|
35
|
+
? 'application/ahtml+json'
|
|
36
|
+
: 'application/ahtml+text';
|
|
37
|
+
// 2) Try a diff request if we already have a snapshot.
|
|
38
|
+
if (cached && !o.noCache) {
|
|
39
|
+
const diffUrl = url + (url.includes('?') ? '&' : '?') + 'since=' + encodeURIComponent(cached.etag ?? '');
|
|
40
|
+
const res = await fetcher(diffUrl, {
|
|
41
|
+
headers: {
|
|
42
|
+
'accept': 'application/ahtml-diff+json, ' + accept,
|
|
43
|
+
...(o.agent && { 'user-agent': o.agent }),
|
|
44
|
+
},
|
|
45
|
+
}).catch((err) => failOrStale(err, cached, o));
|
|
46
|
+
if (res instanceof Response) {
|
|
47
|
+
const ct = res.headers.get('content-type') ?? '';
|
|
48
|
+
if (res.ok && ct.includes('application/ahtml-diff+json')) {
|
|
49
|
+
const d = (await res.json());
|
|
50
|
+
const next = applyDiff(cached.snapshot, d);
|
|
51
|
+
const etag = res.headers.get('etag') ?? d.to_etag;
|
|
52
|
+
this.cache.set(url, { snapshot: next, fetchedAt: Date.now(), etag });
|
|
53
|
+
return next;
|
|
54
|
+
}
|
|
55
|
+
if (res.ok && ct.includes('application/ahtml')) {
|
|
56
|
+
return this.storeFromResponse(url, res);
|
|
57
|
+
}
|
|
58
|
+
if (res.status === 304) {
|
|
59
|
+
this.cache.set(url, { ...cached, fetchedAt: Date.now() });
|
|
60
|
+
return cached.snapshot;
|
|
61
|
+
}
|
|
62
|
+
// anything else — fall through to a fresh fetch
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// 3) Conditional or fresh GET.
|
|
66
|
+
const headers = { accept };
|
|
67
|
+
if (cached?.etag && !o.noCache)
|
|
68
|
+
headers['if-none-match'] = cached.etag;
|
|
69
|
+
if (o.agent)
|
|
70
|
+
headers['user-agent'] = o.agent;
|
|
71
|
+
let res;
|
|
72
|
+
try {
|
|
73
|
+
res = await fetcher(url, { headers });
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const fb = failOrStale(err, cached, o);
|
|
77
|
+
if (fb instanceof Response)
|
|
78
|
+
res = fb;
|
|
79
|
+
else
|
|
80
|
+
throw err;
|
|
81
|
+
}
|
|
82
|
+
if (res.status === 304 && cached) {
|
|
83
|
+
this.cache.set(url, { ...cached, fetchedAt: Date.now() });
|
|
84
|
+
return cached.snapshot;
|
|
85
|
+
}
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
if (cached && o.allowStale)
|
|
88
|
+
return cached.snapshot;
|
|
89
|
+
throw new AHTMLError(res.status, await res.text());
|
|
90
|
+
}
|
|
91
|
+
return this.storeFromResponse(url, res);
|
|
92
|
+
}
|
|
93
|
+
async storeFromResponse(url, res) {
|
|
94
|
+
const ct = res.headers.get('content-type') ?? '';
|
|
95
|
+
const body = await res.text();
|
|
96
|
+
const snapshot = ct.includes('application/ahtml+json')
|
|
97
|
+
? fromJson(body)
|
|
98
|
+
: fromCompact(body);
|
|
99
|
+
const etag = res.headers.get('etag') ?? undefined;
|
|
100
|
+
this.cache.set(url, { snapshot, fetchedAt: Date.now(), etag });
|
|
101
|
+
return snapshot;
|
|
102
|
+
}
|
|
103
|
+
invalidate(url) {
|
|
104
|
+
if (url)
|
|
105
|
+
this.cache.delete(url);
|
|
106
|
+
else
|
|
107
|
+
this.cache.clear();
|
|
108
|
+
}
|
|
109
|
+
/** Discover a site's manifest. Returns the parsed JSON. */
|
|
110
|
+
async manifest(siteOrUrl, opts = {}) {
|
|
111
|
+
const fetcher = opts.fetch ?? globalThis.fetch;
|
|
112
|
+
const base = siteOrUrl.replace(/\/$/, '');
|
|
113
|
+
const url = base.endsWith('/.well-known/ahtml.json')
|
|
114
|
+
? base
|
|
115
|
+
: base + '/.well-known/ahtml.json';
|
|
116
|
+
const res = await fetcher(url, { headers: { accept: 'application/json' } });
|
|
117
|
+
if (!res.ok)
|
|
118
|
+
throw new AHTMLError(res.status, `manifest fetch failed for ${url}`);
|
|
119
|
+
return res.json();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
export class AHTMLError extends Error {
|
|
123
|
+
status;
|
|
124
|
+
constructor(status, message) {
|
|
125
|
+
super(`AHTML ${status}: ${message}`);
|
|
126
|
+
this.status = status;
|
|
127
|
+
this.name = 'AHTMLError';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function isFresh(cached) {
|
|
131
|
+
const ttl = cached.snapshot.ttl;
|
|
132
|
+
if (ttl == null)
|
|
133
|
+
return false;
|
|
134
|
+
return Date.now() - cached.fetchedAt < ttl * 1000;
|
|
135
|
+
}
|
|
136
|
+
function failOrStale(err, cached, o) {
|
|
137
|
+
if (cached && o.allowStale) {
|
|
138
|
+
return new Response(null, { status: 504 }); // signal caller to keep cached
|
|
139
|
+
}
|
|
140
|
+
return err;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,WAAW,EACX,QAAQ,EACR,SAAS,GAGV,MAAM,iBAAiB,CAAC;AAuBzB,MAAM,OAAO,WAAW;IAGF;IAFZ,KAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IAElD,YAAoB,WAAyB,EAAE;QAA3B,aAAQ,GAAR,QAAQ,CAAmB;IAAG,CAAC;IAEnD;;;;OAIG;IACH,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,OAAqB,EAAE;QAC9C,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEnC,2DAA2D;QAC3D,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5C,OAAO,MAAM,CAAC,QAAQ,CAAC;QACzB,CAAC;QAED,MAAM,MAAM,GACV,CAAC,CAAC,MAAM,KAAK,MAAM;YACjB,CAAC,CAAC,wBAAwB;YAC1B,CAAC,CAAC,wBAAwB,CAAC;QAE/B,uDAAuD;QACvD,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,QAAQ,GAAG,kBAAkB,CAAC,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACzG,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE;gBACjC,OAAO,EAAE;oBACP,QAAQ,EAAE,+BAA+B,GAAG,MAAM;oBAClD,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;iBAC1C;aACF,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;YAE/C,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;gBAC5B,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;gBACjD,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CAAC;oBACzD,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAiB,CAAC;oBAC7C,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;oBAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;oBAClD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;oBACrE,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,IAAI,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;oBAC/C,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBAC1C,CAAC;gBACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAC1D,OAAO,MAAM,CAAC,QAAQ,CAAC;gBACzB,CAAC;gBACD,gDAAgD;YAClD,CAAC;QACH,CAAC;QAED,+BAA+B;QAC/B,MAAM,OAAO,GAA2B,EAAE,MAAM,EAAE,CAAC;QACnD,IAAI,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO;YAAE,OAAO,CAAC,eAAe,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC;QACvE,IAAI,CAAC,CAAC,KAAK;YAAE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QAE7C,IAAI,GAAa,CAAC;QAClB,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACxC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;YACvC,IAAI,EAAE,YAAY,QAAQ;gBAAE,GAAG,GAAG,EAAE,CAAC;;gBAChC,MAAM,GAAG,CAAC;QACjB,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,MAAM,EAAE,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YAC1D,OAAO,MAAM,CAAC,QAAQ,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,MAAM,IAAI,CAAC,CAAC,UAAU;gBAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;YACnD,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,GAAW,EAAE,GAAa;QACxD,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;YACpD,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAChB,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACtB,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC;QAClD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,UAAU,CAAC,GAAY;QACrB,IAAI,GAAG;YAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;;YAC3B,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED,2DAA2D;IAC3D,KAAK,CAAC,QAAQ,CAAC,SAAiB,EAAE,OAAqB,EAAE;QACvD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;QAC/C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC;YAClD,CAAC,CAAC,IAAI;YACN,CAAC,CAAC,IAAI,GAAG,yBAAyB,CAAC;QACrC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;QAC5E,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,6BAA6B,GAAG,EAAE,CAAC,CAAC;QAClF,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;CACF;AAED,MAAM,OAAO,UAAW,SAAQ,KAAK;IAChB;IAAnB,YAAmB,MAAc,EAAE,OAAe;QAChD,KAAK,CAAC,SAAS,MAAM,KAAK,OAAO,EAAE,CAAC,CAAC;QADpB,WAAM,GAAN,MAAM,CAAQ;QAE/B,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED,SAAS,OAAO,CAAC,MAAsB;IACrC,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;IAChC,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9B,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,GAAG,GAAG,IAAI,CAAC;AACpD,CAAC;AAED,SAAS,WAAW,CAAC,GAAY,EAAE,MAAkC,EAAE,CAAe;IACpF,IAAI,MAAM,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;QAC3B,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,+BAA+B;IAC7E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ahtmljs/agent — public API.
|
|
3
|
+
*/
|
|
4
|
+
export { AHTMLClient, type FetchOptions, type CachedSnapshot } from './client.js';
|
|
5
|
+
export { runAction, type ActionRunOptions, type ActionResult, type DryRunResult } from './workflow.js';
|
|
6
|
+
export { countTokens, countTokensClaude, countTokensGpt, measure, type TokenMeasurement, } from './tokens.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AACvG,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,OAAO,EACP,KAAK,gBAAgB,GACtB,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,WAAW,EAA0C,MAAM,aAAa,CAAC;AAClF,OAAO,EAAE,SAAS,EAA+D,MAAM,eAAe,CAAC;AACvG,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,cAAc,EACd,OAAO,GAER,MAAM,aAAa,CAAC"}
|
package/dist/tokens.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token measurement using industry-standard tokenizers.
|
|
3
|
+
*
|
|
4
|
+
* gpt-tokenizer — OpenAI's tiktoken (cl100k_base, o200k_base) in pure JS.
|
|
5
|
+
* Used in the vast majority of public token-cost reports.
|
|
6
|
+
* @anthropic-ai/tokenizer — Claude's official BPE tokenizer.
|
|
7
|
+
*
|
|
8
|
+
* Both are peer dependencies — install whichever you need:
|
|
9
|
+
*
|
|
10
|
+
* npm i gpt-tokenizer # OpenAI / GPT-4 / GPT-4o / o-series
|
|
11
|
+
* npm i @anthropic-ai/tokenizer # Anthropic / Claude
|
|
12
|
+
*
|
|
13
|
+
* If the package is not present, the corresponding function throws a
|
|
14
|
+
* helpful error. We do NOT fall back to char/4 — that's the kind of
|
|
15
|
+
* non-rigorous measurement we want this library to be the opposite of.
|
|
16
|
+
*/
|
|
17
|
+
export type TokenizerModel = 'gpt-3.5-turbo' | 'gpt-4' | 'gpt-4o' | 'gpt-4o-mini' | 'o1' | 'o3-mini' | 'claude' | 'claude-haiku' | 'claude-sonnet' | 'claude-opus';
|
|
18
|
+
export interface TokenMeasurement {
|
|
19
|
+
bytes: number;
|
|
20
|
+
bytes_gzip?: number;
|
|
21
|
+
tokens_openai_cl100k?: number;
|
|
22
|
+
tokens_openai_o200k?: number;
|
|
23
|
+
tokens_anthropic?: number;
|
|
24
|
+
}
|
|
25
|
+
/** Count tokens with the OpenAI tiktoken-compatible tokenizer. */
|
|
26
|
+
export declare function countTokensGpt(text: string, encoding?: 'cl100k_base' | 'o200k_base'): Promise<number>;
|
|
27
|
+
/** Count tokens with Anthropic's official Claude tokenizer. */
|
|
28
|
+
export declare function countTokensClaude(text: string): Promise<number>;
|
|
29
|
+
/** Best-effort count for a model name. */
|
|
30
|
+
export declare function countTokens(text: string, model: TokenizerModel): Promise<number>;
|
|
31
|
+
/** Take a snapshot of every metric we care about. Skips unavailable tokenizers gracefully. */
|
|
32
|
+
export declare function measure(text: string, opts?: {
|
|
33
|
+
gzip?: boolean;
|
|
34
|
+
}): Promise<TokenMeasurement>;
|
|
35
|
+
//# sourceMappingURL=tokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,cAAc,GAEtB,eAAe,GACf,OAAO,GACP,QAAQ,GACR,aAAa,GACb,IAAI,GACJ,SAAS,GAET,QAAQ,GACR,cAAc,GACd,eAAe,GACf,aAAa,CAAC;AAElB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,kEAAkE;AAClE,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,aAAa,GAAG,YAA2B,GACpD,OAAO,CAAC,MAAM,CAAC,CAqBjB;AAED,+DAA+D;AAC/D,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAWrE;AAED,0CAA0C;AAC1C,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtF;AAED,8FAA8F;AAC9F,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAYpG"}
|
package/dist/tokens.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token measurement using industry-standard tokenizers.
|
|
3
|
+
*
|
|
4
|
+
* gpt-tokenizer — OpenAI's tiktoken (cl100k_base, o200k_base) in pure JS.
|
|
5
|
+
* Used in the vast majority of public token-cost reports.
|
|
6
|
+
* @anthropic-ai/tokenizer — Claude's official BPE tokenizer.
|
|
7
|
+
*
|
|
8
|
+
* Both are peer dependencies — install whichever you need:
|
|
9
|
+
*
|
|
10
|
+
* npm i gpt-tokenizer # OpenAI / GPT-4 / GPT-4o / o-series
|
|
11
|
+
* npm i @anthropic-ai/tokenizer # Anthropic / Claude
|
|
12
|
+
*
|
|
13
|
+
* If the package is not present, the corresponding function throws a
|
|
14
|
+
* helpful error. We do NOT fall back to char/4 — that's the kind of
|
|
15
|
+
* non-rigorous measurement we want this library to be the opposite of.
|
|
16
|
+
*/
|
|
17
|
+
/** Count tokens with the OpenAI tiktoken-compatible tokenizer. */
|
|
18
|
+
export async function countTokensGpt(text, encoding = 'o200k_base') {
|
|
19
|
+
let tok;
|
|
20
|
+
try {
|
|
21
|
+
const mod = await import('gpt-tokenizer');
|
|
22
|
+
if (encoding === 'o200k_base' && mod.encodeChat) {
|
|
23
|
+
// gpt-tokenizer v3+ exposes per-encoding sub-paths via /encoding/<name>
|
|
24
|
+
try {
|
|
25
|
+
const sub = await import(`gpt-tokenizer/encoding/${encoding}`);
|
|
26
|
+
tok = sub;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
tok = mod;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
tok = mod;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
throw new Error(`gpt-tokenizer not installed. Run: npm i gpt-tokenizer\n${err.message}`);
|
|
38
|
+
}
|
|
39
|
+
return tok.encode(text).length;
|
|
40
|
+
}
|
|
41
|
+
/** Count tokens with Anthropic's official Claude tokenizer. */
|
|
42
|
+
export async function countTokensClaude(text) {
|
|
43
|
+
let tok;
|
|
44
|
+
try {
|
|
45
|
+
const mod = await import('@anthropic-ai/tokenizer');
|
|
46
|
+
tok = mod;
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
throw new Error(`@anthropic-ai/tokenizer not installed. Run: npm i @anthropic-ai/tokenizer\n${err.message}`);
|
|
50
|
+
}
|
|
51
|
+
return tok.countTokens(text);
|
|
52
|
+
}
|
|
53
|
+
/** Best-effort count for a model name. */
|
|
54
|
+
export async function countTokens(text, model) {
|
|
55
|
+
if (model.startsWith('claude'))
|
|
56
|
+
return countTokensClaude(text);
|
|
57
|
+
if (model.startsWith('o') || model === 'gpt-4o' || model === 'gpt-4o-mini') {
|
|
58
|
+
return countTokensGpt(text, 'o200k_base');
|
|
59
|
+
}
|
|
60
|
+
return countTokensGpt(text, 'cl100k_base');
|
|
61
|
+
}
|
|
62
|
+
/** Take a snapshot of every metric we care about. Skips unavailable tokenizers gracefully. */
|
|
63
|
+
export async function measure(text, opts = {}) {
|
|
64
|
+
const out = { bytes: Buffer.byteLength(text, 'utf8') };
|
|
65
|
+
if (opts.gzip !== false) {
|
|
66
|
+
try {
|
|
67
|
+
const zlib = await import('node:zlib');
|
|
68
|
+
out.bytes_gzip = zlib.gzipSync(text, { level: 9 }).length;
|
|
69
|
+
}
|
|
70
|
+
catch { }
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
out.tokens_openai_cl100k = await countTokensGpt(text, 'cl100k_base');
|
|
74
|
+
}
|
|
75
|
+
catch { }
|
|
76
|
+
try {
|
|
77
|
+
out.tokens_openai_o200k = await countTokensGpt(text, 'o200k_base');
|
|
78
|
+
}
|
|
79
|
+
catch { }
|
|
80
|
+
try {
|
|
81
|
+
out.tokens_anthropic = await countTokensClaude(text);
|
|
82
|
+
}
|
|
83
|
+
catch { }
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action execution and dry-run.
|
|
3
|
+
*
|
|
4
|
+
* AHTML actions carry typed contracts (input/output schema, auth, cost,
|
|
5
|
+
* reversibility, side effects, confirmation level). This module gives
|
|
6
|
+
* agents a single function to either *simulate* the action against
|
|
7
|
+
* preview_url or *execute* it against execute_url, with policy gates
|
|
8
|
+
* applied client-side as an extra safety layer.
|
|
9
|
+
*/
|
|
10
|
+
import type { Action, Snapshot } from '@ahtmljs/schema';
|
|
11
|
+
export interface ActionRunOptions {
|
|
12
|
+
/** Override the snapshot's confirmation level. Useful when the caller
|
|
13
|
+
* has already confirmed with the user. */
|
|
14
|
+
confirm?: boolean;
|
|
15
|
+
/** Bearer token for auth: required actions. */
|
|
16
|
+
bearer?: string;
|
|
17
|
+
/** Don't actually call execute_url — hit preview_url and return. */
|
|
18
|
+
dryRun?: boolean;
|
|
19
|
+
/** Skip side-effect safety checks (NOT recommended for autonomous agents). */
|
|
20
|
+
skipChecks?: boolean;
|
|
21
|
+
fetch?: typeof fetch;
|
|
22
|
+
}
|
|
23
|
+
export interface ActionResult<T = unknown> {
|
|
24
|
+
status: 'executed';
|
|
25
|
+
output: T;
|
|
26
|
+
http_status: number;
|
|
27
|
+
}
|
|
28
|
+
export interface DryRunResult {
|
|
29
|
+
status: 'dry_run';
|
|
30
|
+
would_charge?: {
|
|
31
|
+
amount: number;
|
|
32
|
+
currency: string;
|
|
33
|
+
};
|
|
34
|
+
would_email?: string[];
|
|
35
|
+
would_side_effects?: string[];
|
|
36
|
+
preview?: unknown;
|
|
37
|
+
}
|
|
38
|
+
/** Throw when an action's contract conflicts with the agent's policy. */
|
|
39
|
+
export declare class ActionRefused extends Error {
|
|
40
|
+
reason: string;
|
|
41
|
+
constructor(reason: string);
|
|
42
|
+
}
|
|
43
|
+
export declare function runAction<TIn, TOut>(snapshot: Snapshot, action: Action, input: TIn, opts?: ActionRunOptions): Promise<ActionResult<TOut> | DryRunResult>;
|
|
44
|
+
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAC/B;+CAC2C;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO;IACvC,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,CAAC,CAAC;IACV,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,yEAAyE;AACzE,qBAAa,aAAc,SAAQ,KAAK;IACnB,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM;CAGlC;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,IAAI,EACvC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,GAAG,EACV,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CA2C5C"}
|
package/dist/workflow.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action execution and dry-run.
|
|
3
|
+
*
|
|
4
|
+
* AHTML actions carry typed contracts (input/output schema, auth, cost,
|
|
5
|
+
* reversibility, side effects, confirmation level). This module gives
|
|
6
|
+
* agents a single function to either *simulate* the action against
|
|
7
|
+
* preview_url or *execute* it against execute_url, with policy gates
|
|
8
|
+
* applied client-side as an extra safety layer.
|
|
9
|
+
*/
|
|
10
|
+
/** Throw when an action's contract conflicts with the agent's policy. */
|
|
11
|
+
export class ActionRefused extends Error {
|
|
12
|
+
reason;
|
|
13
|
+
constructor(reason) {
|
|
14
|
+
super(`ActionRefused: ${reason}`);
|
|
15
|
+
this.reason = reason;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function runAction(snapshot, action, input, opts = {}) {
|
|
19
|
+
const fetcher = opts.fetch ?? globalThis.fetch;
|
|
20
|
+
if (!opts.skipChecks)
|
|
21
|
+
checkPolicy(snapshot, action, opts);
|
|
22
|
+
// --- Dry run path ---
|
|
23
|
+
if (opts.dryRun || (!action.execute_url && action.preview_url)) {
|
|
24
|
+
if (!action.preview_url) {
|
|
25
|
+
return {
|
|
26
|
+
status: 'dry_run',
|
|
27
|
+
would_charge: extractCost(action),
|
|
28
|
+
would_side_effects: action.side_effects ?? [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const res = await fetcher(action.preview_url, {
|
|
32
|
+
method: 'POST',
|
|
33
|
+
headers: jsonHeaders(opts.bearer),
|
|
34
|
+
body: JSON.stringify(input),
|
|
35
|
+
});
|
|
36
|
+
if (!res.ok)
|
|
37
|
+
throw new Error(`preview failed: ${res.status}`);
|
|
38
|
+
const preview = await res.json().catch(() => undefined);
|
|
39
|
+
return {
|
|
40
|
+
status: 'dry_run',
|
|
41
|
+
would_charge: extractCost(action),
|
|
42
|
+
would_side_effects: action.side_effects ?? [],
|
|
43
|
+
preview,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// --- Execute path ---
|
|
47
|
+
if (!action.execute_url) {
|
|
48
|
+
throw new ActionRefused(`action "${action.id}" has no execute_url`);
|
|
49
|
+
}
|
|
50
|
+
const res = await fetcher(action.execute_url, {
|
|
51
|
+
method: action.method ?? 'POST',
|
|
52
|
+
headers: jsonHeaders(opts.bearer),
|
|
53
|
+
body: JSON.stringify(input),
|
|
54
|
+
});
|
|
55
|
+
const output = (await res.json().catch(() => null));
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
throw new Error(`action "${action.id}" failed: ${res.status}`);
|
|
58
|
+
}
|
|
59
|
+
return { status: 'executed', output, http_status: res.status };
|
|
60
|
+
}
|
|
61
|
+
function checkPolicy(snapshot, action, opts) {
|
|
62
|
+
if (action.auth === 'required' && !opts.bearer) {
|
|
63
|
+
throw new ActionRefused(`action "${action.id}" requires auth but no bearer provided`);
|
|
64
|
+
}
|
|
65
|
+
if (action.confirmation === 'required' && !opts.confirm) {
|
|
66
|
+
throw new ActionRefused(`action "${action.id}" requires explicit confirmation — pass { confirm: true }`);
|
|
67
|
+
}
|
|
68
|
+
if (snapshot.policy?.agents_welcome === false) {
|
|
69
|
+
throw new ActionRefused(`site policy: agents_welcome=false`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function extractCost(action) {
|
|
73
|
+
const c = action.cost;
|
|
74
|
+
if (!c || c.amount == null || !c.currency)
|
|
75
|
+
return undefined;
|
|
76
|
+
return { amount: c.amount, currency: c.currency };
|
|
77
|
+
}
|
|
78
|
+
function jsonHeaders(bearer) {
|
|
79
|
+
const h = { 'content-type': 'application/json' };
|
|
80
|
+
if (bearer)
|
|
81
|
+
h.authorization = `Bearer ${bearer}`;
|
|
82
|
+
return h;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=workflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.js","sourceRoot":"","sources":["../src/workflow.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ahtmljs/agent",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "AHTML agent SDK — fetch snapshots, cache by ETag, run actions with dry-run support, and measure token cost using industry-standard tokenizers.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
|
|
10
|
+
"./tokens": { "types": "./dist/tokens.d.ts", "import": "./dist/tokens.js" }
|
|
11
|
+
},
|
|
12
|
+
"files": ["dist"],
|
|
13
|
+
"publishConfig": { "access": "public" },
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json",
|
|
16
|
+
"dev": "tsc -p tsconfig.json --watch"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@ahtmljs/schema": "0.1.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^22.0.0"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"gpt-tokenizer": "^3.0.0",
|
|
26
|
+
"@anthropic-ai/tokenizer": "^0.0.4"
|
|
27
|
+
},
|
|
28
|
+
"peerDependenciesMeta": {
|
|
29
|
+
"gpt-tokenizer": { "optional": true },
|
|
30
|
+
"@anthropic-ai/tokenizer": { "optional": true }
|
|
31
|
+
},
|
|
32
|
+
"keywords": ["ahtml", "agent", "mcp", "llm", "tokenizer", "crawler"],
|
|
33
|
+
"license": "MIT"
|
|
34
|
+
}
|