@wenathlan/getry 2.0.166 → 2.0.168
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 +1 -1
- package/cli.ts +15 -6
- package/db.ts +33 -29
- package/docs/features.md +1 -2
- package/docs/gateway.md +2 -3
- package/gatewaycheck.ts +142 -0
- package/package.json +81 -89
- package/server.ts +9 -5
- package/{tests → test}/cli.test.ts +1 -1
- package/{tests → test}/design.test.ts +3 -3
- package/test/familyseats.test.ts +220 -0
- package/{tests → test}/gateway.test.ts +2 -2
- package/{tests → test}/gatewayversions.test.ts +1 -1
- package/{tests → test}/intelligence.test.ts +1 -1
- package/{tests → test}/keyrotation.test.ts +1 -1
- package/{tests → test}/onboardingstate.test.ts +1 -1
- package/{tests → test}/providerfixtures.ts +12 -12
- package/{tests → test}/researchfixtures.ts +1 -1
- package/{tests → test}/sandboxmodality.test.ts +1 -1
- package/gatewayprobe.ts +0 -61
- package/gatewaysmoke.ts +0 -64
- /package/{tests → test}/debonairlane.test.ts +0 -0
- /package/{tests → test}/family.test.ts +0 -0
- /package/{tests → test}/gatewayserver.ts +0 -0
- /package/{tests → test}/jsonpolicy.test.ts +0 -0
- /package/{tests → test}/llm.test.ts +0 -0
- /package/{tests → test}/modelroute.test.ts +0 -0
- /package/{tests → test}/promptlibrary.test.ts +0 -0
- /package/{tests → test}/providercli.test.ts +0 -0
- /package/{tests → test}/providerconstants.test.ts +0 -0
- /package/{tests → test}/providerfingerprint.test.ts +0 -0
- /package/{tests → test}/providermodels.test.ts +0 -0
- /package/{tests → test}/provideroauth.test.ts +0 -0
- /package/{tests → test}/routerotation.test.ts +0 -0
- /package/{tests → test}/serverauth.test.ts +0 -0
- /package/{tests → test}/serverengine.test.ts +0 -0
- /package/{tests → test}/serverproperty.test.ts +0 -0
- /package/{tests → test}/serverutils.test.ts +0 -0
- /package/{tests → test}/streamfallback.test.ts +0 -0
- /package/{tests → test}/thinkingladder.test.ts +0 -0
- /package/{tests → test}/torturellm.test.ts +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// # familyseats.test — the two family seats battery (runnable with the
|
|
2
|
+
// vitest runner):
|
|
3
|
+
// pnpm vitest run test/familyseats.test.ts
|
|
4
|
+
//
|
|
5
|
+
// The laws the battery pins (the owner's rules, the two gateway/account
|
|
6
|
+
// lane seats):
|
|
7
|
+
// 1. the gateway ports law (law 39 — "Gateway proxy ports: host/porta
|
|
8
|
+
// sorteados, never localhost literal", beside the anti localhost law
|
|
9
|
+
// the corpus records — "random host octets, port drawn from the
|
|
10
|
+
// cryptographic band 30000 to 59999"): the gateway boot never answers
|
|
11
|
+
// a literal host or port — the env pin rides when the env carries one,
|
|
12
|
+
// otherwise the port draws inside the documented cryptographic band
|
|
13
|
+
// (30000..59999, the saddle orchestrator grammar crypto.randomInt(30000)
|
|
14
|
+
// + 30000) and the host draws inside the loopback band 127.x.y.z with
|
|
15
|
+
// three drawn octets; the retired literal fallbacks (the || 3001 chain,
|
|
16
|
+
// the "0.0.0.0" host) answer nowhere in the gateway lane sources;
|
|
17
|
+
// 2. the one signup law (law 40 — "One signup family-wide (guest identity
|
|
18
|
+
// never deleted)", beside the family sharing law the corpus records —
|
|
19
|
+
// "one signup and one account recognized in every app... the guest
|
|
20
|
+
// identity born on the first visit and never deleted"): the family
|
|
21
|
+
// carries ONE signup lane (the vault person's door, POST
|
|
22
|
+
// /api/v1/auth/signup over signupAccount in vault/account.ts) and the
|
|
23
|
+
// visitor identity rows ride zero delete lanes family-wide — the
|
|
24
|
+
// onboarding lanes upsert seen-wins (ON CONFLICT(visitor) DO UPDATE)
|
|
25
|
+
// and no sweep, retention or cleanup ever deletes the guest.
|
|
26
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
27
|
+
import { dirname, join } from "node:path";
|
|
28
|
+
import { fileURLToPath } from "node:url";
|
|
29
|
+
import { describe, expect, it } from "vitest";
|
|
30
|
+
import { drawgatewayhost, drawgatewayport, gatewayportband, resolvegatewaybind } from "../binddraw.ts";
|
|
31
|
+
|
|
32
|
+
/** the monorepo root resolved from this test file location. */
|
|
33
|
+
const monoreporoot = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
34
|
+
|
|
35
|
+
/** the family app roots (the deploy units the law names). */
|
|
36
|
+
const FAMILYROOTS = [
|
|
37
|
+
"argan",
|
|
38
|
+
"cadria",
|
|
39
|
+
"cobaia",
|
|
40
|
+
"debonair",
|
|
41
|
+
"devthink",
|
|
42
|
+
"forge",
|
|
43
|
+
"foundry",
|
|
44
|
+
"getry",
|
|
45
|
+
"saddle",
|
|
46
|
+
"stealthhead",
|
|
47
|
+
"vault",
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
/** the walks the source scan skips (the tests-are-exempt law rides the
|
|
51
|
+
* test fixtures, the build ghosts never ride the tree). */
|
|
52
|
+
const SKIPNAMES = new Set(["node_modules", "dist", "build", "test", "tests", ".git"]);
|
|
53
|
+
|
|
54
|
+
/** walks every .ts/.tsx source under one app root (skips the exempt lanes). */
|
|
55
|
+
function walksources(relroot: string): string[] {
|
|
56
|
+
const out: string[] = [];
|
|
57
|
+
const walk = (absdir: string): void => {
|
|
58
|
+
for (const entry of readdirSync(absdir)) {
|
|
59
|
+
const abs = join(absdir, entry);
|
|
60
|
+
const st = statSync(abs);
|
|
61
|
+
if (st.isDirectory()) {
|
|
62
|
+
if (SKIPNAMES.has(entry)) continue;
|
|
63
|
+
walk(abs);
|
|
64
|
+
} else if ((entry.endsWith(".ts") || entry.endsWith(".tsx")) && !entry.endsWith(".d.ts")) {
|
|
65
|
+
out.push(abs);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
walk(join(monoreporoot, relroot));
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** reads one repo file as text (repo-root relative). */
|
|
74
|
+
function source(relative: string): string {
|
|
75
|
+
return readFileSync(join(monoreporoot, relative), "utf8");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
describe("the gateway ports law (host/porta sorteados, never localhost literal)", () => {
|
|
79
|
+
it("draws the port inside the documented cryptographic band 30000..59999", () => {
|
|
80
|
+
const draws = new Set<number>();
|
|
81
|
+
for (let i = 0; i < 400; i += 1) {
|
|
82
|
+
const port = drawgatewayport();
|
|
83
|
+
expect(port).toBeGreaterThanOrEqual(gatewayportband.first);
|
|
84
|
+
expect(port).toBeLessThanOrEqual(gatewayportband.last);
|
|
85
|
+
draws.add(port);
|
|
86
|
+
}
|
|
87
|
+
// the band answers a real draw, not a degenerate constant
|
|
88
|
+
expect(draws.size).toBeGreaterThanOrEqual(100);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("draws the host inside the loopback band 127.x.y.z with three drawn octets", () => {
|
|
92
|
+
const draws = new Set<string>();
|
|
93
|
+
for (let i = 0; i < 200; i += 1) {
|
|
94
|
+
const host = drawgatewayhost();
|
|
95
|
+
const match = host.match(/^127\.(\d+)\.(\d+)\.(\d+)$/);
|
|
96
|
+
expect(match, `the drawn host ${host} rides 127.a.b.c`).not.toBeNull();
|
|
97
|
+
if (!match) continue;
|
|
98
|
+
for (const octet of match.slice(1)) {
|
|
99
|
+
const value = Number(octet);
|
|
100
|
+
expect(value).toBeGreaterThanOrEqual(1);
|
|
101
|
+
expect(value).toBeLessThanOrEqual(254);
|
|
102
|
+
}
|
|
103
|
+
draws.add(host);
|
|
104
|
+
}
|
|
105
|
+
expect(draws.size).toBeGreaterThanOrEqual(50);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("rides the env pin when the env carries one (the pin is a pin, never a literal)", () => {
|
|
109
|
+
const pinned = resolvegatewaybind("41234", "127.9.9.9");
|
|
110
|
+
expect(pinned.port).toBe(41234);
|
|
111
|
+
expect(pinned.hostname).toBe("127.9.9.9");
|
|
112
|
+
expect(pinned.portdrawn).toBe(false);
|
|
113
|
+
expect(pinned.hostdrawn).toBe(false);
|
|
114
|
+
// an env value the operator set rides verbatim — the law bans the source
|
|
115
|
+
// literal fallback, never the operator's own pin
|
|
116
|
+
const operatorpin = resolvegatewaybind("3001", undefined);
|
|
117
|
+
expect(operatorpin.port).toBe(3001);
|
|
118
|
+
expect(operatorpin.portdrawn).toBe(false);
|
|
119
|
+
expect(operatorpin.hostdrawn).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("draws when the env stays silent or lies (empty, zero, negative, junk)", () => {
|
|
123
|
+
for (const [portenv, hostenv] of [
|
|
124
|
+
[undefined, undefined],
|
|
125
|
+
["", ""],
|
|
126
|
+
[" ", " "],
|
|
127
|
+
["0", undefined],
|
|
128
|
+
["-1", ""],
|
|
129
|
+
["abc", undefined],
|
|
130
|
+
] as const) {
|
|
131
|
+
const drawn = resolvegatewaybind(portenv, hostenv);
|
|
132
|
+
expect(drawn.portdrawn, `PORT=${String(portenv)} must not pin`).toBe(true);
|
|
133
|
+
expect(drawn.port).toBeGreaterThanOrEqual(gatewayportband.first);
|
|
134
|
+
expect(drawn.port).toBeLessThanOrEqual(gatewayportband.last);
|
|
135
|
+
expect(drawn.hostdrawn, `HOST=${String(hostenv)} must not pin`).toBe(true);
|
|
136
|
+
expect(drawn.hostname).toMatch(/^127\.\d+\.\d+\.\d+$/);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("carries no literal bind fallback in the gateway lane sources", () => {
|
|
141
|
+
const servertxt = source("getry/server.ts");
|
|
142
|
+
expect(servertxt, "the transport main retired the || 3001 chain").not.toMatch(/\|\|\s*3001/);
|
|
143
|
+
expect(servertxt, "the transport main retired the 0.0.0.0 host").not.toContain('"0.0.0.0"');
|
|
144
|
+
expect(servertxt, "the transport main rides the drawn bind resolver").toContain("resolvegatewaybind(");
|
|
145
|
+
const clitxt = source("getry/cli.ts");
|
|
146
|
+
expect(clitxt, "the console serve seat retired the || 3001 chain").not.toMatch(/\|\|\s*3001/);
|
|
147
|
+
expect(clitxt, "the console serve seat retired the 0.0.0.0 host").not.toContain('"0.0.0.0"');
|
|
148
|
+
const bindtxt = source("getry/binddraw.ts");
|
|
149
|
+
expect(bindtxt, "the draw rides node:crypto randomInt").toContain('from "node:crypto"');
|
|
150
|
+
expect(bindtxt, "the port draw names the documented band").toMatch(/30000/);
|
|
151
|
+
// the localhost literal answers nowhere in the gateway boot lane
|
|
152
|
+
for (const file of ["getry/server.ts", "getry/cli.ts", "getry/binddraw.ts"]) {
|
|
153
|
+
expect(source(file), `${file} carries no localhost bind literal`).not.toMatch(/localhost:\d+/);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("keeps the oauth callback seat on the os draw (port 0, env pin)", () => {
|
|
158
|
+
const oauthtxt = source("getry/oauth.ts");
|
|
159
|
+
expect(oauthtxt, "the callback server asks the os for the port").toMatch(/server\.listen\(0,/);
|
|
160
|
+
expect(oauthtxt, "the callback pin rides the env, never a literal").toContain("OAUTH_CALLBACK_PORT");
|
|
161
|
+
expect(oauthtxt, "the callback host rides the env loopback, never 0.0.0.0").not.toContain('"0.0.0.0"');
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("the one signup law (one signup family-wide, the guest identity never deleted)", () => {
|
|
166
|
+
it("carries one signup lane — the vault person's door, and no sibling mounts one", () => {
|
|
167
|
+
const routestxt = source("vault/routes.ts");
|
|
168
|
+
expect(routestxt, "the one signup door rides the vault route table").toContain('signup: "/api/v1/auth/signup"');
|
|
169
|
+
const accounttxt = source("vault/account.ts");
|
|
170
|
+
expect(accounttxt, "the signup account lane lives in the vault account seat").toContain(
|
|
171
|
+
"export function signupAccount(",
|
|
172
|
+
);
|
|
173
|
+
expect(accounttxt, "the signup http door answers the route").toMatch(/POST \/api\/v1\/auth\/signup/);
|
|
174
|
+
// no sibling carries the signup lane (the walk answers only vault files)
|
|
175
|
+
const carriers: string[] = [];
|
|
176
|
+
for (const root of FAMILYROOTS) {
|
|
177
|
+
for (const file of walksources(root)) {
|
|
178
|
+
const text = readFileSync(file, "utf8");
|
|
179
|
+
if (text.includes("signupAccount") || text.includes("/api/v1/auth/signup")) carriers.push(file);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const strangers = carriers.filter((file) => !file.replaceAll("\\", "/").includes("/vault/"));
|
|
183
|
+
expect(strangers, `only vault carries the signup lane — strangers answered: ${strangers.join(", ")}`).toEqual([]);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("upserts the visitor identity seen-wins — born on the first write, never replayed", () => {
|
|
187
|
+
expect(source("vault/db.ts"), "the vault onboarding lane upserts").toMatch(/ON CONFLICT\(visitor\) DO UPDATE SET/);
|
|
188
|
+
expect(source("vault/onboardingstore.ts"), "the onboarding store lane upserts").toMatch(
|
|
189
|
+
/ON CONFLICT\(visitor\) DO UPDATE SET/,
|
|
190
|
+
);
|
|
191
|
+
expect(source("getry/db.ts"), "the getry onboarding lane upserts").toMatch(/ON CONFLICT\(visitor\) DO UPDATE/);
|
|
192
|
+
expect(source("vault/db.ts"), "the visitor row rides the platform db").toMatch(
|
|
193
|
+
/CREATE TABLE IF NOT EXISTS onboarding_states/,
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("carries zero delete lanes against the visitor and person identity rows family-wide", () => {
|
|
198
|
+
// the identity rows: the visitor's onboarding_states and the person's
|
|
199
|
+
// accounts — no source in the family ever deletes them
|
|
200
|
+
const identitydelete = /DELETE\s+FROM\s+(IF\s+EXISTS\s+)?"?(onboarding_states|accounts|visitors|visitor)"?\b/i;
|
|
201
|
+
const carriers: string[] = [];
|
|
202
|
+
for (const root of FAMILYROOTS) {
|
|
203
|
+
for (const file of walksources(root)) {
|
|
204
|
+
const text = readFileSync(file, "utf8");
|
|
205
|
+
if (identitydelete.test(text)) carriers.push(file);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
expect(carriers, `the guest identity never deletes — carriers answered: ${carriers.join(", ")}`).toEqual([]);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("keeps the sweep lanes honest — the retention clock plans, it never deletes an identity", () => {
|
|
212
|
+
const retentiontxt = source("vault/retention.ts");
|
|
213
|
+
expect(retentiontxt, "the retention engine is a pure plan").not.toMatch(/\bDELETE\s+FROM\b/i);
|
|
214
|
+
expect(retentiontxt, "the retention clock never rides an identity lane").not.toMatch(/visitor|account/i);
|
|
215
|
+
const objectstxt = source("vault/objects.ts");
|
|
216
|
+
expect(objectstxt, "the object sweep never rides an identity lane").not.toMatch(
|
|
217
|
+
/DELETE\s+FROM\s+"?(onboarding_states|accounts)/i,
|
|
218
|
+
);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
@@ -889,9 +889,9 @@ describe("hardcoded provider url scan of the source tree", () => {
|
|
|
889
889
|
const outsidescan = new Set([...gatewaysources, "providers.ts", "gateway.ts", "types.ts"]);
|
|
890
890
|
for (const entry of await readdir(root))
|
|
891
891
|
if (entry.endsWith(".ts") && !outsidescan.has(entry)) files.push(join(root, entry));
|
|
892
|
-
for (const entry of await readdir(join(root, "
|
|
892
|
+
for (const entry of await readdir(join(root, "test")))
|
|
893
893
|
if (entry.endsWith(".ts") && !entry.endsWith(".test.ts") && entry !== "reviewedorigins.ts")
|
|
894
|
-
files.push(join(root, "
|
|
894
|
+
files.push(join(root, "test", entry));
|
|
895
895
|
expect(files.length).toBeGreaterThan(40);
|
|
896
896
|
const providerhosts = [
|
|
897
897
|
/api\.openai\.com/,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* through the thinking seat. the suite pins its own DATABASE_URL before the
|
|
7
7
|
* db import so the mirror opens its own seat (one writer per wal file — the
|
|
8
8
|
* SQLITE_BUSY lesson). runnable with vitest:
|
|
9
|
-
* pnpm vitest run
|
|
9
|
+
* pnpm vitest run test/gatewayversions.test.ts
|
|
10
10
|
*/
|
|
11
11
|
import assert from "node:assert/strict";
|
|
12
12
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// provenance and metrics domain rides its new owner — the battery
|
|
6
6
|
// answers the same contracts the engine suite once pinned: the rag
|
|
7
7
|
// chunking, the retrieval provenance and the token budget trio).
|
|
8
|
-
// runnable with vitest: pnpm vitest run
|
|
8
|
+
// runnable with vitest: pnpm vitest run test/intelligence.test.ts
|
|
9
9
|
import assert from "node:assert/strict";
|
|
10
10
|
import { describe, it } from "vitest";
|
|
11
11
|
import {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* the health-aware round-robin of nextkeyrow (the pr19 key rotation law —
|
|
4
4
|
* never expose keys, rotation periods, per-provider health) beside the
|
|
5
5
|
* masking discipline the render paths owe. runnable with vitest:
|
|
6
|
-
* pnpm vitest run
|
|
6
|
+
* pnpm vitest run test/keyrotation.test.ts
|
|
7
7
|
*/
|
|
8
8
|
import assert from "node:assert/strict";
|
|
9
9
|
import { describe, it } from "vitest";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// # onboardingstate.test — the pure contract of the seen flags: the host
|
|
2
2
|
// validation of the platform base (https only, public hosts only, mapped
|
|
3
3
|
// ipv6 normalized) and the seen-wins stage merge the accessor and the
|
|
4
|
-
// pages share. runnable with vitest: pnpm vitest run
|
|
4
|
+
// pages share. runnable with vitest: pnpm vitest run test/onboardingstate.test.ts
|
|
5
5
|
import assert from "node:assert/strict";
|
|
6
6
|
import { describe, it } from "vitest";
|
|
7
7
|
import { hostallowed, mergeStage } from "../onboardingstate.ts";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** The recorded provider wire fixtures of the gateway family as one dense typescript module: the streams, the completions, the model lists and the tags answer of the four provider shapes (anthropic, gemini, ollama and the openai compatible surface), each export holding the exact original file text of its tests root source. The localhost gateway fixture server serves them over plain http so the adapter suite and the container smoke run the full request cycle offline — no external network, no provider endpoint, no key — and the gateway tests parse the same bodies the stub transports answer. */
|
|
2
2
|
|
|
3
|
-
/** the anthropic message stream (sse events of the content block delta family) — the exact text of the former
|
|
3
|
+
/** the anthropic message stream (sse events of the content block delta family) — the exact text of the former test/anthropic-stream.txt. */
|
|
4
4
|
export const anthropicstream = `event: message_start
|
|
5
5
|
data: {"type":"message_start","message":{"id":"msg-fixture-1","role":"assistant"}}
|
|
6
6
|
|
|
@@ -24,7 +24,7 @@ data: {"type":"message_stop"}
|
|
|
24
24
|
|
|
25
25
|
`;
|
|
26
26
|
|
|
27
|
-
/** the anthropic completion answer (the stop reason and the usage record) — the exact text of the former
|
|
27
|
+
/** the anthropic completion answer (the stop reason and the usage record) — the exact text of the former test/anthropic-completion.json. */
|
|
28
28
|
export const anthropiccompletion = `{
|
|
29
29
|
"id": "msg-fixture-1",
|
|
30
30
|
"type": "message",
|
|
@@ -41,7 +41,7 @@ export const anthropiccompletion = `{
|
|
|
41
41
|
}
|
|
42
42
|
`;
|
|
43
43
|
|
|
44
|
-
/** the anthropic model list (the fixture claude shapes with their context windows) — the exact text of the former
|
|
44
|
+
/** the anthropic model list (the fixture claude shapes with their context windows) — the exact text of the former test/anthropic-models.json. */
|
|
45
45
|
export const anthropicmodels = `{
|
|
46
46
|
"data": [
|
|
47
47
|
{
|
|
@@ -61,7 +61,7 @@ export const anthropicmodels = `{
|
|
|
61
61
|
}
|
|
62
62
|
`;
|
|
63
63
|
|
|
64
|
-
/** the gemini generatecontent stream (the sse quoted-json chunks of the streamed answer) — the exact text of the former
|
|
64
|
+
/** the gemini generatecontent stream (the sse quoted-json chunks of the streamed answer) — the exact text of the former test/gemini-stream.txt. */
|
|
65
65
|
export const geministream = `data: {"candidates":[{"content":{"parts":[{"text":"gemini "}],"role":"model"},"index":0}]}
|
|
66
66
|
|
|
67
67
|
data: {"candidates":[{"content":{"parts":[{"text":"candidate parts "}],"role":"model"},"index":0}]}
|
|
@@ -70,7 +70,7 @@ data: {"candidates":[{"content":{"parts":[{"text":"stream"}],"role":"model"},"in
|
|
|
70
70
|
|
|
71
71
|
`;
|
|
72
72
|
|
|
73
|
-
/** the gemini completion answer (the candidates with the finish reason) — the exact text of the former
|
|
73
|
+
/** the gemini completion answer (the candidates with the finish reason) — the exact text of the former test/gemini-completion.json. */
|
|
74
74
|
export const geminicompletion = `{
|
|
75
75
|
"candidates": [
|
|
76
76
|
{
|
|
@@ -86,7 +86,7 @@ export const geminicompletion = `{
|
|
|
86
86
|
}
|
|
87
87
|
`;
|
|
88
88
|
|
|
89
|
-
/** the gemini model list (the fixture gemini shapes) — the exact text of the former
|
|
89
|
+
/** the gemini model list (the fixture gemini shapes) — the exact text of the former test/gemini-models.json. */
|
|
90
90
|
export const geminimodels = `{
|
|
91
91
|
"models": [
|
|
92
92
|
{
|
|
@@ -106,13 +106,13 @@ export const geminimodels = `{
|
|
|
106
106
|
}
|
|
107
107
|
`;
|
|
108
108
|
|
|
109
|
-
/** the ollama chat stream (the ndjson lines of the streamed answer) — the exact text of the former
|
|
109
|
+
/** the ollama chat stream (the ndjson lines of the streamed answer) — the exact text of the former test/ollama-stream.txt. */
|
|
110
110
|
export const ollamastream = `{"model":"fixture-local:7b","created_at":"2026-01-01T00:00:00Z","message":{"role":"assistant","content":"the local "},"done":false}
|
|
111
111
|
{"model":"fixture-local:7b","created_at":"2026-01-01T00:00:00Z","message":{"role":"assistant","content":"runtime streams "},"done":false}
|
|
112
112
|
{"model":"fixture-local:7b","created_at":"2026-01-01T00:00:00Z","message":{"role":"assistant","content":"line by line"},"done":true}
|
|
113
113
|
`;
|
|
114
114
|
|
|
115
|
-
/** the ollama chat completion answer (the message and the done record) — the exact text of the former
|
|
115
|
+
/** the ollama chat completion answer (the message and the done record) — the exact text of the former test/ollama-completion.json. */
|
|
116
116
|
export const ollamacompletion = `{
|
|
117
117
|
"model": "fixture-local:7b",
|
|
118
118
|
"created_at": "2026-01-01T00:00:00Z",
|
|
@@ -126,7 +126,7 @@ export const ollamacompletion = `{
|
|
|
126
126
|
}
|
|
127
127
|
`;
|
|
128
128
|
|
|
129
|
-
/** the ollama tags answer (the local model list with sizes and digests) — the exact text of the former
|
|
129
|
+
/** the ollama tags answer (the local model list with sizes and digests) — the exact text of the former test/ollama-tags.json. */
|
|
130
130
|
export const ollamatags = `{
|
|
131
131
|
"models": [
|
|
132
132
|
{
|
|
@@ -161,7 +161,7 @@ export const ollamatags = `{
|
|
|
161
161
|
}
|
|
162
162
|
`;
|
|
163
163
|
|
|
164
|
-
/** the openai compatible chat stream (the sse chunks of the streamed answer) — the exact text of the former
|
|
164
|
+
/** the openai compatible chat stream (the sse chunks of the streamed answer) — the exact text of the former test/openaicompat-stream.txt. */
|
|
165
165
|
export const openaicompatstream = `data: {"id":"chatcmpl-fixture-1","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"{\\"goal\\":"}}]}
|
|
166
166
|
|
|
167
167
|
data: {"id":"chatcmpl-fixture-1","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"\\"streamed answer\\","}}]}
|
|
@@ -172,7 +172,7 @@ data: [DONE]
|
|
|
172
172
|
|
|
173
173
|
`;
|
|
174
174
|
|
|
175
|
-
/** the openai compatible chat completion answer (the choices with the message and the usage) — the exact text of the former
|
|
175
|
+
/** the openai compatible chat completion answer (the choices with the message and the usage) — the exact text of the former test/openaicompat-completion.json. */
|
|
176
176
|
export const openaicompatcompletion = `{
|
|
177
177
|
"id": "chatcmpl-fixture-1",
|
|
178
178
|
"object": "chat.completion",
|
|
@@ -191,7 +191,7 @@ export const openaicompatcompletion = `{
|
|
|
191
191
|
}
|
|
192
192
|
`;
|
|
193
193
|
|
|
194
|
-
/** the openai compatible model list (the fixture model shapes) — the exact text of the former
|
|
194
|
+
/** the openai compatible model list (the fixture model shapes) — the exact text of the former test/openaicompat-models.json. */
|
|
195
195
|
export const openaicompatmodels = `{
|
|
196
196
|
"object": "list",
|
|
197
197
|
"data": [
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** The public research catalog sources as one dense typescript module: the twelve public github search exports beside the two markdown documents the catalog build derives from them, each export holding the exact original file text of its
|
|
1
|
+
/** The public research catalog sources as one dense typescript module: the twelve public github search exports beside the two markdown documents the catalog build derives from them, each export holding the exact original file text of its test/code source. The exports record source metadata only — the catalog build never downloads or executes repository code — and the markdown documents carry the licensed sample, the method notes and the comparative feature and flow matrix the research review reads. */
|
|
2
2
|
|
|
3
3
|
/** The public repository metadata of the browser agent search export (one recorded repository), harvested from the public github search index on 2026-08-27 — the exact text of the former reposagent.json. */
|
|
4
4
|
export const reposagent = `[
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// modality id pins the seat for the platform's join to validate at
|
|
10
10
|
// dispatch — this module never judges engine vocabulary). runnable with
|
|
11
11
|
// vitest:
|
|
12
|
-
// pnpm vitest run
|
|
12
|
+
// pnpm vitest run test/sandboxmodality.test.ts
|
|
13
13
|
import assert from "node:assert/strict";
|
|
14
14
|
import { describe, it } from "vitest";
|
|
15
15
|
import { lanesof } from "@wenathlan/saddle/workloadlaw";
|
package/gatewayprobe.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* gatewayprobe.ts — manual chat round trip against a deployed DevThink
|
|
3
|
-
* gateway (the ZAI sandbox deploy of the getry template). This probe is
|
|
4
|
-
* NOT wired into the deterministic gates: it needs the live network and
|
|
5
|
-
* the deployed host is a runtime setting, never a tracked constant of a
|
|
6
|
-
* gate. Run it by hand with the base URL as the first argument:
|
|
7
|
-
*
|
|
8
|
-
* node gatewayprobe.ts https://<deployed-gateway-host>
|
|
9
|
-
*
|
|
10
|
-
* The probe exercises the exact surface the Sol chat client consumes:
|
|
11
|
-
* GET /v1/models (the picker) and POST /v1/chat/completions with the
|
|
12
|
-
* model "devthink" (content + reasoning_content on the answer turn).
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const base = (process.argv[2] ?? "").replace(/\/+$/, "");
|
|
16
|
-
|
|
17
|
-
if (!/^https?:\/\//.test(base)) {
|
|
18
|
-
console.error("usage: node gatewayprobe.ts https://<deployed-gateway-host>");
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/* GET /v1/models — the chat picker surface. */
|
|
23
|
-
const models = await fetch(`${base}/v1/models`);
|
|
24
|
-
if (!models.ok) {
|
|
25
|
-
console.error(`models probe failed: ${models.status}`);
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
const modellist = (await models.json()) as { data?: Array<{ id?: string }> };
|
|
29
|
-
const ids = (modellist.data ?? []).map((m) => m.id);
|
|
30
|
-
console.log(`models: ${ids.join(", ") || "(none)"}`);
|
|
31
|
-
|
|
32
|
-
/* POST /v1/chat/completions — one round trip on the chat surface. */
|
|
33
|
-
const chat = await fetch(`${base}/v1/chat/completions`, {
|
|
34
|
-
method: "POST",
|
|
35
|
-
headers: { "content-type": "application/json" },
|
|
36
|
-
body: JSON.stringify({
|
|
37
|
-
model: "devthink",
|
|
38
|
-
messages: [{ role: "user", content: "Reply with exactly: gateway ok" }],
|
|
39
|
-
max_tokens: 20,
|
|
40
|
-
}),
|
|
41
|
-
});
|
|
42
|
-
if (!chat.ok) {
|
|
43
|
-
console.error(`chat probe failed: ${chat.status}`);
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
const answer = (await chat.json()) as {
|
|
47
|
-
choices?: Array<{ message?: { content?: string; reasoning_content?: string } }>;
|
|
48
|
-
usage?: unknown;
|
|
49
|
-
};
|
|
50
|
-
const turn = answer.choices?.[0]?.message;
|
|
51
|
-
console.log(`chat: ${JSON.stringify(turn?.content ?? "")}`);
|
|
52
|
-
console.log(`reasoning present: ${Boolean(turn?.reasoning_content)}`);
|
|
53
|
-
console.log(`usage: ${JSON.stringify(answer.usage ?? {})}`);
|
|
54
|
-
|
|
55
|
-
if (turn?.content !== "gateway ok") {
|
|
56
|
-
console.error("the gateway answered, but the round trip content drifted");
|
|
57
|
-
process.exit(1);
|
|
58
|
-
}
|
|
59
|
-
console.log("gateway probe: ok");
|
|
60
|
-
|
|
61
|
-
export {};
|
package/gatewaysmoke.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/** The containerfile gateway smoke of the 1.1.83 family: it starts the localhost fixture server, loads the built gateway module and runs one full request cycle against the recorded openaicompat fixture offline — no provider endpoint, no key, no external network — so the container image proves the gateway call path before it ships. */
|
|
2
|
-
import { startgatewayfixtureserver } from "./tests/gatewayserver.ts";
|
|
3
|
-
import type { baseurlconfig } from "./types.ts";
|
|
4
|
-
|
|
5
|
-
const server = await startgatewayfixtureserver();
|
|
6
|
-
try {
|
|
7
|
-
/* the smoke loads the BUILT gateway module — build/llm.js is a container
|
|
8
|
-
* build artifact a fresh checkout never carries, so the specifier rides a
|
|
9
|
-
* variable (tsc never fails on the absent artifact while the runtime
|
|
10
|
-
* keeps loading the built face) and the cast pins the module to the
|
|
11
|
-
* source contract that sits beside it. */
|
|
12
|
-
const builtpath = "./build/llm.js";
|
|
13
|
-
const gateway = (await import(builtpath)) as typeof import("./llm.ts");
|
|
14
|
-
const config: baseurlconfig = {
|
|
15
|
-
providerid: "smoke",
|
|
16
|
-
kind: "openaicompat",
|
|
17
|
-
baseurl: `http://127.0.0.1:${server.port}/openaicompat`,
|
|
18
|
-
enabled: true,
|
|
19
|
-
consented: true,
|
|
20
|
-
consentedat: Date.now(),
|
|
21
|
-
updatedat: Date.now(),
|
|
22
|
-
};
|
|
23
|
-
const outcome = await gateway.gatewaycall({
|
|
24
|
-
config,
|
|
25
|
-
model: "fixture-model-a",
|
|
26
|
-
messages: [{ role: "user", content: "draft one step" }],
|
|
27
|
-
requestid: "smoke-1",
|
|
28
|
-
transport: async (url: string, init: { method: string; headers: Record<string, string>; body?: string }) => {
|
|
29
|
-
const response = await fetch(url, { method: init.method, headers: init.headers, body: init.body });
|
|
30
|
-
return {
|
|
31
|
-
status: response.status,
|
|
32
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
33
|
-
body: await response.text(),
|
|
34
|
-
};
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
if (!outcome.text.includes("goal")) throw new Error("The gateway smoke answer carries no goal field.");
|
|
38
|
-
if (outcome.usage?.totaltokens !== 55) throw new Error("The gateway smoke usage did not parse.");
|
|
39
|
-
const streamed = await gateway.gatewaystream({
|
|
40
|
-
config: { ...config, providerid: "smoke-stream" },
|
|
41
|
-
model: "fixture-model-a",
|
|
42
|
-
messages: [{ role: "user", content: "stream" }],
|
|
43
|
-
transport: async (url: string, init: { method: string; headers: Record<string, string>; body?: string }) => {
|
|
44
|
-
const response = await fetch(url, { method: init.method, headers: init.headers, body: init.body });
|
|
45
|
-
return {
|
|
46
|
-
status: response.status,
|
|
47
|
-
headers: Object.fromEntries(response.headers.entries()),
|
|
48
|
-
body: await response.text(),
|
|
49
|
-
};
|
|
50
|
-
},
|
|
51
|
-
});
|
|
52
|
-
if (streamed.tokens.length !== 3)
|
|
53
|
-
throw new Error("The gateway smoke stream did not carry the three recorded deltas.");
|
|
54
|
-
console.log(
|
|
55
|
-
JSON.stringify({
|
|
56
|
-
valid: true,
|
|
57
|
-
requestid: outcome.requestid,
|
|
58
|
-
tokens: streamed.tokens.length,
|
|
59
|
-
usage: outcome.usage.totaltokens,
|
|
60
|
-
}),
|
|
61
|
-
);
|
|
62
|
-
} finally {
|
|
63
|
-
await server.close();
|
|
64
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|