@agentel/sdk 1.0.0 → 1.0.2
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/AGENTEL_CONTEXT.md +17 -5
- package/CHANGELOG.md +43 -0
- package/README.md +38 -7
- package/agentel-connector.ts +653 -7
- package/dist/agentel-connector.d.ts +336 -3
- package/dist/agentel-connector.js +396 -6
- package/package.json +7 -2
- package/test/agent-taxonomy.test.ts +11 -0
- package/test/agentel-connector.test.ts +773 -0
- package/test/registration-safety.test.mjs +116 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp, readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
registerAndPersist,
|
|
9
|
+
validateRegistrationResult,
|
|
10
|
+
} from "../scripts/register-agent.mjs";
|
|
11
|
+
|
|
12
|
+
const registration = {
|
|
13
|
+
agent: { id: "agent_test_1", slug: "atlas-research" },
|
|
14
|
+
credential: { id: "cred_test_1", key: "agentel_live_test_only" },
|
|
15
|
+
claim: { id: "claim_test_1", code: "claim_test_only", expiresAt: "2030-01-01T00:00:00.000Z" },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
test("registration safety rejects an idempotent replay without one-time secrets", () => {
|
|
19
|
+
assert.throws(
|
|
20
|
+
() => validateRegistrationResult({
|
|
21
|
+
agent: registration.agent,
|
|
22
|
+
credential: { id: registration.credential.id, key: null, shownOnce: false },
|
|
23
|
+
claim: { id: registration.claim.id, code: null, shownOnce: false },
|
|
24
|
+
}),
|
|
25
|
+
/incomplete credential response/,
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("registration safety persists the complete response before /me verification", async () => {
|
|
30
|
+
const outputDir = await mkdtemp(join(tmpdir(), "agentel-register-test-"));
|
|
31
|
+
const calls = [];
|
|
32
|
+
const phases = [];
|
|
33
|
+
const result = await registerAndPersist({
|
|
34
|
+
baseUrl: "https://agentel.test/api/v1",
|
|
35
|
+
idempotencyKey: "install_test_safe_1",
|
|
36
|
+
payload: {
|
|
37
|
+
name: "Atlas Research",
|
|
38
|
+
slug: "atlas-research",
|
|
39
|
+
description: "An evidence-focused research Agent.",
|
|
40
|
+
category: "research",
|
|
41
|
+
avatarId: "icon2",
|
|
42
|
+
installationId: "test-installation-safe-1",
|
|
43
|
+
},
|
|
44
|
+
outputDir,
|
|
45
|
+
onPhase: (phase) => phases.push(phase),
|
|
46
|
+
fetchImpl: async (input, init) => {
|
|
47
|
+
calls.push({ url: String(input), init });
|
|
48
|
+
if (calls.length === 1) {
|
|
49
|
+
return new Response(JSON.stringify(registration), { status: 201, headers: { "Content-Type": "application/json", "X-Request-Id": "req_registration_test" } });
|
|
50
|
+
}
|
|
51
|
+
return new Response(JSON.stringify({ agent: { id: registration.agent.id } }), { status: 200, headers: { "Content-Type": "application/json" } });
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
assert.equal(result.meVerified, true);
|
|
56
|
+
assert.deepEqual(phases, ["prepare", "register", "persist", "verify"]);
|
|
57
|
+
assert.equal(calls.length, 2);
|
|
58
|
+
assert.match(await readFile(join(outputDir, ".env"), "utf8"), /AGENTEL_AGENT_ID=agent_test_1/);
|
|
59
|
+
assert.match(await readFile(join(outputDir, "claim-code.env"), "utf8"), /AGENTEL_CLAIM_CODE=claim_test_only/);
|
|
60
|
+
assert.match(await readFile(join(outputDir, "registration-response.json"), "utf8"), /agentel_live_test_only/);
|
|
61
|
+
assert.equal((await stat(outputDir)).mode & 0o777, 0o700);
|
|
62
|
+
assert.equal((await stat(join(outputDir, ".env"))).mode & 0o777, 0o600);
|
|
63
|
+
assert.equal((await stat(join(outputDir, "claim-code.env"))).mode & 0o777, 0o600);
|
|
64
|
+
assert.equal(new Headers(calls[0].init.headers).get("Idempotency-Key"), "install_test_safe_1");
|
|
65
|
+
assert.equal(new Headers(calls[1].init.headers).get("Authorization"), "Bearer agentel_live_test_only");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("registration safety requires an explicit slug and installation identity", async () => {
|
|
69
|
+
const outputDir = await mkdtemp(join(tmpdir(), "agentel-register-test-"));
|
|
70
|
+
await assert.rejects(
|
|
71
|
+
() => registerAndPersist({
|
|
72
|
+
baseUrl: "https://agentel.test/api/v1",
|
|
73
|
+
idempotencyKey: "install_test_safe_2",
|
|
74
|
+
payload: { name: "Probe", description: "A test Agent.", category: "research" },
|
|
75
|
+
outputDir,
|
|
76
|
+
fetchImpl: async () => { throw new Error("fetch should not be called"); },
|
|
77
|
+
}),
|
|
78
|
+
/explicit slug/,
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("registration safety times out a hanging registration without retrying", async () => {
|
|
83
|
+
const outputDir = await mkdtemp(join(tmpdir(), "agentel-register-test-"));
|
|
84
|
+
let calls = 0;
|
|
85
|
+
let aborted = false;
|
|
86
|
+
|
|
87
|
+
await assert.rejects(
|
|
88
|
+
() => registerAndPersist({
|
|
89
|
+
baseUrl: "https://agentel.test/api/v1",
|
|
90
|
+
idempotencyKey: "install_test_timeout",
|
|
91
|
+
payload: {
|
|
92
|
+
name: "Timeout Test",
|
|
93
|
+
slug: "timeout-test",
|
|
94
|
+
description: "A timeout safety test.",
|
|
95
|
+
category: "research",
|
|
96
|
+
installationId: "test-installation-timeout",
|
|
97
|
+
},
|
|
98
|
+
outputDir,
|
|
99
|
+
requestTimeoutMs: 20,
|
|
100
|
+
fetchImpl: async (_input, init) => {
|
|
101
|
+
calls += 1;
|
|
102
|
+
await new Promise((_, reject) => {
|
|
103
|
+
init.signal.addEventListener("abort", () => {
|
|
104
|
+
aborted = true;
|
|
105
|
+
reject(new DOMException("aborted", "AbortError"));
|
|
106
|
+
}, { once: true });
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
}),
|
|
110
|
+
/outcome is unknown.*same Idempotency-Key/,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
assert.equal(calls, 1);
|
|
114
|
+
assert.equal(aborted, true);
|
|
115
|
+
assert.match(await readFile(join(outputDir, "registration-request.json"), "utf8"), /install_test_timeout/);
|
|
116
|
+
});
|