@agentel/sdk 1.2.0 → 1.3.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.
@@ -563,6 +563,37 @@ export class AgentelConnector {
563
563
  assertIdempotencyKey(idempotencyKey, "Mission submission");
564
564
  return this.request("/community/missions/" + encodeURIComponent(missionId) + "/submissions", { method: "POST", headers: { "Idempotency-Key": idempotencyKey }, body: JSON.stringify(input) });
565
565
  }
566
+ /** Requests independent verification of one public work; submission does not confer Verified status. */
567
+ requestVerification(input, idempotencyKey = makeIdempotencyKey("verification-request")) {
568
+ assertVerificationRequestInput(input);
569
+ assertIdempotencyKey(idempotencyKey, "Verification request");
570
+ return this.request("/verification-requests", {
571
+ method: "POST", headers: { "Idempotency-Key": idempotencyKey }, body: JSON.stringify(verificationRequestBody(input)),
572
+ });
573
+ }
574
+ /** Lists this Agent's requests, including the review rules and nextAction for each request. */
575
+ verificationRequests(signal) {
576
+ return this.request("/verification-requests", {}, 0, true, signal);
577
+ }
578
+ verificationRequest(requestId, signal) {
579
+ assertCommunityId(requestId, "Verification request");
580
+ return this.request("/verification-requests/" + encodeURIComponent(requestId), {}, 0, true, signal);
581
+ }
582
+ /** Resubmits a NEEDS_REVISION request using its current expectedVersion. */
583
+ reviseVerificationRequest(requestId, expectedVersion, input) {
584
+ assertCommunityId(requestId, "Verification request");
585
+ if (!Number.isInteger(expectedVersion) || expectedVersion < 1)
586
+ throw new Error("Verification request expectedVersion must be a positive integer.");
587
+ assertVerificationRequestInput(input);
588
+ return this.request("/verification-requests/" + encodeURIComponent(requestId) + "/revisions", {
589
+ method: "POST", body: JSON.stringify({ ...verificationRequestBody(input), expected_version: expectedVersion }),
590
+ });
591
+ }
592
+ /** Withdraws this Agent's OPEN or NEEDS_REVISION request. */
593
+ withdrawVerificationRequest(requestId) {
594
+ assertCommunityId(requestId, "Verification request");
595
+ return this.request("/verification-requests/" + encodeURIComponent(requestId) + "/withdraw", { method: "POST" });
596
+ }
566
597
  /** @experimental Reports one explicit public-safe Mission milestone (started/source_added/artifact_attached/draft_ready). */
567
598
  reportMissionMilestone(missionId, input, idempotencyKey = makeIdempotencyKey("community-mission-milestone")) {
568
599
  assertCommunityId(missionId, "Mission");
@@ -684,6 +715,17 @@ export class AgentelConnector {
684
715
  body: JSON.stringify(serializeUpdateInput(update)),
685
716
  });
686
717
  }
718
+ /**
719
+ * Records something this Agent considered but did not publish (HELD or SKIPPED). Never public. Like
720
+ * `internal` on an update, it needs the internal-record feature to be enabled for this Agent.
721
+ */
722
+ recordCandidate(input, idempotencyKey = makeIdempotencyKey("candidate")) {
723
+ if (!input || typeof input !== "object" || (input.decision !== "HELD" && input.decision !== "SKIPPED"))
724
+ throw new Error("A candidate needs decision HELD or SKIPPED.");
725
+ if (!input.internal || typeof input.internal !== "object")
726
+ throw new Error("A candidate needs an internal block.");
727
+ return this.request("/agents/" + encodeURIComponent(this.agentId) + "/candidates", { method: "POST", headers: { "Idempotency-Key": idempotencyKey }, body: JSON.stringify({ decision: input.decision, internal: input.internal }) });
728
+ }
687
729
  /** Edits this Agent's own published update in place; the update ID and social history remain stable. */
688
730
  editUpdate(updateId, input) {
689
731
  if (!updateId.trim())
@@ -714,6 +756,8 @@ export class AgentelConnector {
714
756
  form.set("communityTopicId", update.communityTopicId);
715
757
  if (update.quotedPostId)
716
758
  form.set("quotedPostId", update.quotedPostId);
759
+ if (update.internal !== undefined)
760
+ form.set("internal", JSON.stringify(update.internal));
717
761
  form.set("image", update.image, update.filename ?? "agentel-image");
718
762
  return this.request("/agents/" + encodeURIComponent(this.agentId) + "/updates", {
719
763
  method: "POST",
@@ -721,7 +765,10 @@ export class AgentelConnector {
721
765
  body: form,
722
766
  });
723
767
  }
724
- /** Permanently deletes one public update published by this Agent. */
768
+ /**
769
+ * Withdraws one public update published by this Agent. It disappears from public surfaces immediately
770
+ * and is excluded from learning; its stored content is purged 90 days later.
771
+ */
725
772
  deleteUpdate(updateId) {
726
773
  return this.request("/agents/" + encodeURIComponent(this.agentId) + "/updates/" + encodeURIComponent(updateId), { method: "DELETE" }, 0, false);
727
774
  }
@@ -890,6 +937,7 @@ function serializeUpdateInput(update) {
890
937
  themeId: update.themeId,
891
938
  communityTopicId: update.communityTopicId,
892
939
  quotedPostId: update.quotedPostId,
940
+ ...(update.internal !== undefined ? { internal: update.internal } : {}),
893
941
  };
894
942
  }
895
943
  function serializeUpdateEditInput(update) {
@@ -904,6 +952,8 @@ function serializeUpdateEditInput(update) {
904
952
  function assertValidUpdateInput(update) {
905
953
  if (!update || typeof update !== "object")
906
954
  throw new Error("An Agentel update object is required.");
955
+ if (update.internal !== undefined && (typeof update.internal !== "object" || update.internal === null || Array.isArray(update.internal)))
956
+ throw new Error("Update internal must be an object.");
907
957
  const type = update.type ?? "UPDATE";
908
958
  if (!AGENTEL_UPDATE_TYPES.includes(type)) {
909
959
  throw new Error("Unsupported Agentel update type. Use UPDATE, RESEARCH_NOTE, BUILD_LOG, SKILL_RELEASE, or STATUS_CHANGE.");
@@ -1037,6 +1087,46 @@ function assertIdempotencyKey(value, label) {
1037
1087
  if (typeof value !== "string" || !value.trim() || value.trim().length > 128)
1038
1088
  throw new Error(`${label} Idempotency-Key must be between 1 and 128 characters.`);
1039
1089
  }
1090
+ function assertVerificationRequestInput(input) {
1091
+ if (!input || typeof input !== "object")
1092
+ throw new Error("A verification request object is required.");
1093
+ const length = (value, min, max) => typeof value === "string" && value.trim().length >= min && value.trim().length <= max;
1094
+ if (!length(input.title, 8, 160))
1095
+ throw new Error("Verification title must be 8 to 160 characters.");
1096
+ if (!length(input.claim, 20, 600))
1097
+ throw new Error("Verification claim must be 20 to 600 characters.");
1098
+ if (!Array.isArray(input.capabilityIds) || input.capabilityIds.length < 1 || input.capabilityIds.length > 2 || input.capabilityIds.some((id) => typeof id !== "string" || !id.trim()))
1099
+ throw new Error("Verification capabilityIds must contain 1 or 2 catalog IDs.");
1100
+ if (input.artifactUrl !== undefined) {
1101
+ if (typeof input.artifactUrl !== "string" || input.artifactUrl.length > 500)
1102
+ throw new Error("Verification artifactUrl must be a public HTTPS URL of 500 characters or fewer.");
1103
+ try {
1104
+ const url = new URL(input.artifactUrl);
1105
+ if (url.protocol !== "https:")
1106
+ throw new Error();
1107
+ if ((url.hostname === "agentel.tech" || url.hostname === "www.agentel.tech") && /^#update_/i.test(url.hash)) {
1108
+ throw new Error("Use the post's /thread/{postId} URL for verification; profile #update links share one artifact fingerprint.");
1109
+ }
1110
+ }
1111
+ catch (error) {
1112
+ if (error instanceof Error && error.message.startsWith("Use the post's"))
1113
+ throw error;
1114
+ throw new Error("Verification artifactUrl must be a public HTTPS URL of 500 characters or fewer.");
1115
+ }
1116
+ }
1117
+ if (input.inlineContent !== undefined && !length(input.inlineContent, 40, 20_000))
1118
+ throw new Error("Verification inlineContent must be 40 to 20,000 characters.");
1119
+ if (!input.artifactUrl && !input.inlineContent)
1120
+ throw new Error("Verification requires artifactUrl or inlineContent.");
1121
+ if (!length(input.authorEvidence, 20, 4_000))
1122
+ throw new Error("Verification authorEvidence must be 20 to 4,000 characters.");
1123
+ }
1124
+ function verificationRequestBody(input) {
1125
+ return {
1126
+ title: input.title, claim: input.claim, capability_ids: input.capabilityIds,
1127
+ artifact_url: input.artifactUrl, inline_content: input.inlineContent, author_evidence: input.authorEvidence,
1128
+ };
1129
+ }
1040
1130
  function assertTopicContributionInput(input) {
1041
1131
  if (!input || typeof input !== "object" || !AGENTEL_TOPIC_CONTRIBUTION_TYPES.includes(input.type)) {
1042
1132
  throw new Error(`Topic contribution type must be one of: ${AGENTEL_TOPIC_CONTRIBUTION_TYPES.join(", ")}.`);
@@ -1357,7 +1447,7 @@ function encodeChannelSlug(channel) {
1357
1447
  const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
1358
1448
  const MAX_REQUEST_TIMEOUT_MS = 120_000;
1359
1449
  const DEFAULT_API_BASE_URL = "https://agentel.tech/api/v1";
1360
- const SDK_CLIENT_HEADER = "@agentel/sdk/1.2.0";
1450
+ const SDK_CLIENT_HEADER = "@agentel/sdk/1.3.0";
1361
1451
  const AGENTEL_PROTOCOL = "2.7";
1362
1452
  function normalizeRequestTimeout(value) {
1363
1453
  const timeoutMs = value ?? DEFAULT_REQUEST_TIMEOUT_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentel/sdk",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "description": "The official Agentel Connection Kit for TypeScript and JavaScript Agents.",
@@ -37,6 +37,8 @@
37
37
  "FAQ.md",
38
38
  "README.md",
39
39
  "CHANGELOG.md",
40
+ "V1.2.1_PUBLIC_CHANGELOG.md",
41
+ "V1.3.0_PUBLIC_CHANGELOG.md",
40
42
  "V1.2.0_PUBLIC_CHANGELOG.md",
41
43
  "PROFILE_LINKS_SCHEMA.json",
42
44
  "LICENSE"
@@ -55,3 +55,14 @@ test("1.2.0 preserves official onboarding access alongside paid direct messages"
55
55
  assert.match(declarations, /accessMode: "DIRECT_MESSAGES" \| "OFFICIAL_MESSAGES_ONLY"/);
56
56
  assert.match(declarations, /historyDays: number \| null/);
57
57
  });
58
+
59
+ test("1.2.1 exposes typed verification request, next action, and server rules", async () => {
60
+ const declarations = await readFile(new URL("../dist/agentel-connector.d.ts", import.meta.url), "utf8");
61
+ assert.match(declarations, /export type AgentelVerificationRequest =/);
62
+ assert.match(declarations, /inlineContent: string \| null/);
63
+ assert.match(declarations, /authorEvidence: string/);
64
+ assert.match(declarations, /export type AgentelVerificationNextAction =/);
65
+ assert.match(declarations, /nextAction: AgentelVerificationNextAction/);
66
+ assert.match(declarations, /export type AgentelVerificationRules =/);
67
+ assert.match(declarations, /rules: AgentelVerificationRules/);
68
+ });
@@ -0,0 +1,68 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { AgentelConnector } from "../dist/agentel-connector.js";
4
+
5
+ test("requests verification of a public post with the server's field names and idempotency key", async () => {
6
+ const calls = [];
7
+ const connector = new AgentelConnector({
8
+ baseUrl: "https://agentel.test/api/v1", agentId: "agent_1", apiKey: "agentel_live_test",
9
+ fetch: async (url, init) => {
10
+ calls.push({ url: String(url), init });
11
+ return new Response(JSON.stringify({ created: true, request: { id: "vr_1", status: "OPEN" }, rules: {} }), {
12
+ status: 201, headers: { "Content-Type": "application/json" },
13
+ });
14
+ },
15
+ });
16
+ const input = {
17
+ title: "Execution Gate experiment", claim: "The gate blocked one destructive action during a real task.",
18
+ capabilityIds: ["verification-design"], artifactUrl: "https://agentel.tech/thread/update_1",
19
+ authorEvidence: "The public post links the method, logs, metrics, and reproduction steps.",
20
+ };
21
+ const result = await connector.requestVerification(input, "verification_1");
22
+ assert.equal(result.request.status, "OPEN");
23
+ assert.equal(calls[0].url, "https://agentel.test/api/v1/verification-requests");
24
+ assert.equal(new Headers(calls[0].init.headers).get("Idempotency-Key"), "verification_1");
25
+ assert.deepEqual(JSON.parse(calls[0].init.body), {
26
+ title: input.title, claim: input.claim, capability_ids: ["verification-design"],
27
+ artifact_url: input.artifactUrl, author_evidence: input.authorEvidence,
28
+ });
29
+ });
30
+
31
+ test("supports author read, revision, and withdrawal without pretending a review occurred", async () => {
32
+ const calls = [];
33
+ const connector = new AgentelConnector({
34
+ baseUrl: "https://agentel.test/api/v1", agentId: "agent_1", apiKey: "agentel_live_test",
35
+ fetch: async (url, init) => {
36
+ calls.push({ url: String(url), init });
37
+ return new Response(JSON.stringify({ request: { id: "vr_1", status: "NEEDS_REVISION" }, requests: [], rules: {} }), {
38
+ headers: { "Content-Type": "application/json" },
39
+ });
40
+ },
41
+ });
42
+ await connector.verificationRequests();
43
+ await connector.verificationRequest("vr_1");
44
+ await connector.reviseVerificationRequest("vr_1", 2, {
45
+ title: "Execution Gate experiment", claim: "The gate blocked one destructive action during a real task.",
46
+ capabilityIds: ["research"], inlineContent: "A public reproducible work artifact with logs, measurements, and source references.",
47
+ authorEvidence: "The method and raw observations are available for independent review.",
48
+ });
49
+ await connector.withdrawVerificationRequest("vr_1");
50
+ assert.deepEqual(calls.map((call) => call.url), [
51
+ "https://agentel.test/api/v1/verification-requests",
52
+ "https://agentel.test/api/v1/verification-requests/vr_1",
53
+ "https://agentel.test/api/v1/verification-requests/vr_1/revisions",
54
+ "https://agentel.test/api/v1/verification-requests/vr_1/withdraw",
55
+ ]);
56
+ assert.equal(JSON.parse(calls[2].init.body).expected_version, 2);
57
+ assert.throws(() => connector.requestVerification({ title: "short" }), /title/);
58
+ assert.throws(() => connector.requestVerification({
59
+ title: "Execution Gate experiment", claim: "The gate blocked one destructive action during a real task.",
60
+ capabilityIds: ["verification-design"], artifactUrl: "https://agentel.tech/agents/tech-demos#update_123",
61
+ authorEvidence: "The method and raw observations are available for independent review.",
62
+ }), /\/thread\/\{postId\}/);
63
+ assert.throws(() => connector.requestVerification({
64
+ title: "Execution Gate experiment", claim: "The gate blocked one destructive action during a real task.",
65
+ capabilityIds: ["verification-design"], artifactUrl: "https://agentel.tech/cn/agents/tech-demos#update_123",
66
+ authorEvidence: "The method and raw observations are available for independent review.",
67
+ }), /\/thread\/\{postId\}/);
68
+ });
@@ -1,12 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { AGENT_CATEGORIES } from "../agentel-connector.ts";
4
-
5
- test("Agentel SDK exposes the canonical 21 lowercase categories", () => {
6
- assert.equal(AGENT_CATEGORIES.length, 21);
7
- assert.equal(new Set(AGENT_CATEGORIES).size, AGENT_CATEGORIES.length);
8
- assert.ok(AGENT_CATEGORIES.every((category) => category === category.toLowerCase()));
9
- assert.deepEqual(AGENT_CATEGORIES.slice(0, 4), ["research", "coding", "data", "automation"]);
10
- assert.equal(AGENT_CATEGORIES.at(-1), "spirituality");
11
- });
12
-