@answerloops/agent-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 ADDED
@@ -0,0 +1,50 @@
1
+ # @answerloops/agent-sdk
2
+
3
+ Typed Node/browser client for the [answerLoops Agent API](https://answerloops.com/docs/integrations/agent-api) — search the knowledge base, read the FAQ digest, list/create tickets, and generate grounded answers.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @answerloops/agent-sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { AgentClient } from "@answerloops/agent-sdk";
15
+
16
+ const client = new AgentClient({
17
+ apiKey: process.env.ANSWERLOOPS_API_KEY!, // al_live_...
18
+ // baseUrl: "https://your-self-hosted-instance.example.com", // defaults to https://answerloops.com
19
+ });
20
+
21
+ const { results } = await client.searchKb({ query: "how do I reset my api key" });
22
+
23
+ const answer = await client.generateAnswer({ question: "How do I reset my API key?" });
24
+
25
+ const ticket = await client.createTicket({ content: "My webhook stopped firing." });
26
+
27
+ const { tickets } = await client.getTickets({ status: "open", limit: 10 });
28
+ ```
29
+
30
+ Every key carries least-privilege scopes (`kb:read`, `faq:read`, `tickets:read`, `tickets:write`, `answers:write`) set in **Settings → API Keys**. A call against a scope the key doesn't have throws `AgentApiError` with `status === 403`.
31
+
32
+ ## Errors
33
+
34
+ Non-2xx responses throw `AgentApiError`:
35
+
36
+ ```ts
37
+ import { AgentApiError } from "@answerloops/agent-sdk";
38
+
39
+ try {
40
+ await client.generateAnswer({ question: "..." });
41
+ } catch (err) {
42
+ if (err instanceof AgentApiError) {
43
+ console.error(err.status, err.body);
44
+ }
45
+ }
46
+ ```
47
+
48
+ ## License
49
+
50
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AgentApiError: () => AgentApiError,
24
+ AgentClient: () => AgentClient
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/client.ts
29
+ var AgentApiError = class extends Error {
30
+ status;
31
+ body;
32
+ constructor(status, body, message) {
33
+ super(message);
34
+ this.name = "AgentApiError";
35
+ this.status = status;
36
+ this.body = body;
37
+ }
38
+ };
39
+ var DEFAULT_BASE_URL = "https://answerloops.com";
40
+ var AgentClient = class {
41
+ apiKey;
42
+ baseUrl;
43
+ fetchImpl;
44
+ constructor(options) {
45
+ if (!options.apiKey) {
46
+ throw new Error("AgentClient requires an apiKey (Settings -> API Keys).");
47
+ }
48
+ this.apiKey = options.apiKey;
49
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
50
+ this.fetchImpl = options.fetch ?? fetch;
51
+ }
52
+ /** GET /api/agent/kb/search — requires the `kb:read` scope. */
53
+ searchKb(params) {
54
+ const query = new URLSearchParams({ query: params.query });
55
+ if (params.limit !== void 0) query.set("limit", String(params.limit));
56
+ return this.request("GET", `/api/agent/kb/search?${query}`);
57
+ }
58
+ /** GET /api/agent/faq — requires the `faq:read` scope. */
59
+ getFaq() {
60
+ return this.request("GET", "/api/agent/faq");
61
+ }
62
+ /** GET /api/agent/tickets — requires the `tickets:read` scope. */
63
+ getTickets(params = {}) {
64
+ const query = new URLSearchParams();
65
+ if (params.status) query.set("status", params.status);
66
+ if (params.priority) query.set("priority", params.priority);
67
+ if (params.category) query.set("category", params.category);
68
+ if (params.limit !== void 0) query.set("limit", String(params.limit));
69
+ const qs = query.toString();
70
+ return this.request("GET", `/api/agent/tickets${qs ? `?${qs}` : ""}`);
71
+ }
72
+ /** POST /api/agent/tickets — requires the `tickets:write` scope. */
73
+ createTicket(params) {
74
+ return this.request("POST", "/api/agent/tickets", {
75
+ content: params.content,
76
+ authorName: params.authorName,
77
+ idempotencyKey: params.idempotencyKey
78
+ });
79
+ }
80
+ /** POST /api/agent/answers — requires the `answers:write` scope. */
81
+ generateAnswer(params) {
82
+ return this.request("POST", "/api/agent/answers", { question: params.question });
83
+ }
84
+ async request(method, path, body) {
85
+ const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
86
+ method,
87
+ headers: {
88
+ Authorization: `Bearer ${this.apiKey}`,
89
+ ...body ? { "Content-Type": "application/json" } : {}
90
+ },
91
+ body: body ? JSON.stringify(body) : void 0
92
+ });
93
+ const text = await res.text();
94
+ const data = text ? JSON.parse(text) : void 0;
95
+ if (!res.ok) {
96
+ throw new AgentApiError(
97
+ res.status,
98
+ data,
99
+ data?.error ?? `Agent API request failed: ${res.status}`
100
+ );
101
+ }
102
+ return data;
103
+ }
104
+ };
105
+ // Annotate the CommonJS export names for ESM import in node:
106
+ 0 && (module.exports = {
107
+ AgentApiError,
108
+ AgentClient
109
+ });
@@ -0,0 +1,95 @@
1
+ interface KbSearchResult {
2
+ question: string;
3
+ answer: string;
4
+ score: number;
5
+ }
6
+ interface KbSearchResponse {
7
+ results: KbSearchResult[];
8
+ }
9
+ type TicketStatus = "open" | "in_progress" | "resolved" | "closed";
10
+ type TicketPriority = "critical" | "high" | "medium" | "low";
11
+ type TicketCategory = "bug" | "feature_request" | "documentation" | "how_to" | "general_question";
12
+ interface Ticket {
13
+ id: number;
14
+ content: string;
15
+ category: TicketCategory | null;
16
+ priority: string;
17
+ status: string;
18
+ ai_summary: string | null;
19
+ created_at: string;
20
+ }
21
+ interface GetTicketsParams {
22
+ status?: TicketStatus;
23
+ priority?: TicketPriority;
24
+ category?: TicketCategory;
25
+ /** 1-20, defaults to 10 */
26
+ limit?: number;
27
+ }
28
+ interface GetTicketsResponse {
29
+ tickets: Ticket[];
30
+ }
31
+ interface CreateTicketParams {
32
+ /** The user's question or issue, verbatim. Max 4000 characters. */
33
+ content: string;
34
+ /** Name/identifier of the end user this ticket is on behalf of. */
35
+ authorName?: string;
36
+ /** Retrying with the same key returns the original ticket instead of opening a duplicate. */
37
+ idempotencyKey?: string;
38
+ }
39
+ interface GenerateAnswerParams {
40
+ /** Max 2000 characters. */
41
+ question: string;
42
+ }
43
+ interface GenerateAnswerResponse {
44
+ answer: string;
45
+ confidence: number;
46
+ answered_fully: boolean;
47
+ high_confidence: boolean;
48
+ }
49
+ interface SearchKbParams {
50
+ /** Max 2000 characters. */
51
+ query: string;
52
+ /** 1-20, defaults to 5 */
53
+ limit?: number;
54
+ }
55
+ /** Shape of the `Error` schema returned on 400/401/403/429 responses. */
56
+ interface AgentApiErrorBody {
57
+ error: string;
58
+ [key: string]: unknown;
59
+ }
60
+
61
+ interface AgentClientOptions {
62
+ /** API key from Settings -> API Keys, `al_live_...`. Shared with the MCP server. */
63
+ apiKey: string;
64
+ /**
65
+ * Base URL of the answerLoops instance. Defaults to the hosted cloud
66
+ * (`https://answerloops.com`). Point this at a self-hosted instance instead.
67
+ */
68
+ baseUrl?: string;
69
+ /** Overrides the global `fetch` — mainly for tests. */
70
+ fetch?: typeof fetch;
71
+ }
72
+ declare class AgentApiError extends Error {
73
+ readonly status: number;
74
+ readonly body: AgentApiErrorBody | undefined;
75
+ constructor(status: number, body: AgentApiErrorBody | undefined, message: string);
76
+ }
77
+ declare class AgentClient {
78
+ private readonly apiKey;
79
+ private readonly baseUrl;
80
+ private readonly fetchImpl;
81
+ constructor(options: AgentClientOptions);
82
+ /** GET /api/agent/kb/search — requires the `kb:read` scope. */
83
+ searchKb(params: SearchKbParams): Promise<KbSearchResponse>;
84
+ /** GET /api/agent/faq — requires the `faq:read` scope. */
85
+ getFaq(): Promise<unknown>;
86
+ /** GET /api/agent/tickets — requires the `tickets:read` scope. */
87
+ getTickets(params?: GetTicketsParams): Promise<GetTicketsResponse>;
88
+ /** POST /api/agent/tickets — requires the `tickets:write` scope. */
89
+ createTicket(params: CreateTicketParams): Promise<Ticket>;
90
+ /** POST /api/agent/answers — requires the `answers:write` scope. */
91
+ generateAnswer(params: GenerateAnswerParams): Promise<GenerateAnswerResponse>;
92
+ private request;
93
+ }
94
+
95
+ export { AgentApiError, type AgentApiErrorBody, AgentClient, type AgentClientOptions, type CreateTicketParams, type GenerateAnswerParams, type GenerateAnswerResponse, type GetTicketsParams, type GetTicketsResponse, type KbSearchResponse, type KbSearchResult, type SearchKbParams, type Ticket, type TicketCategory, type TicketPriority, type TicketStatus };
@@ -0,0 +1,95 @@
1
+ interface KbSearchResult {
2
+ question: string;
3
+ answer: string;
4
+ score: number;
5
+ }
6
+ interface KbSearchResponse {
7
+ results: KbSearchResult[];
8
+ }
9
+ type TicketStatus = "open" | "in_progress" | "resolved" | "closed";
10
+ type TicketPriority = "critical" | "high" | "medium" | "low";
11
+ type TicketCategory = "bug" | "feature_request" | "documentation" | "how_to" | "general_question";
12
+ interface Ticket {
13
+ id: number;
14
+ content: string;
15
+ category: TicketCategory | null;
16
+ priority: string;
17
+ status: string;
18
+ ai_summary: string | null;
19
+ created_at: string;
20
+ }
21
+ interface GetTicketsParams {
22
+ status?: TicketStatus;
23
+ priority?: TicketPriority;
24
+ category?: TicketCategory;
25
+ /** 1-20, defaults to 10 */
26
+ limit?: number;
27
+ }
28
+ interface GetTicketsResponse {
29
+ tickets: Ticket[];
30
+ }
31
+ interface CreateTicketParams {
32
+ /** The user's question or issue, verbatim. Max 4000 characters. */
33
+ content: string;
34
+ /** Name/identifier of the end user this ticket is on behalf of. */
35
+ authorName?: string;
36
+ /** Retrying with the same key returns the original ticket instead of opening a duplicate. */
37
+ idempotencyKey?: string;
38
+ }
39
+ interface GenerateAnswerParams {
40
+ /** Max 2000 characters. */
41
+ question: string;
42
+ }
43
+ interface GenerateAnswerResponse {
44
+ answer: string;
45
+ confidence: number;
46
+ answered_fully: boolean;
47
+ high_confidence: boolean;
48
+ }
49
+ interface SearchKbParams {
50
+ /** Max 2000 characters. */
51
+ query: string;
52
+ /** 1-20, defaults to 5 */
53
+ limit?: number;
54
+ }
55
+ /** Shape of the `Error` schema returned on 400/401/403/429 responses. */
56
+ interface AgentApiErrorBody {
57
+ error: string;
58
+ [key: string]: unknown;
59
+ }
60
+
61
+ interface AgentClientOptions {
62
+ /** API key from Settings -> API Keys, `al_live_...`. Shared with the MCP server. */
63
+ apiKey: string;
64
+ /**
65
+ * Base URL of the answerLoops instance. Defaults to the hosted cloud
66
+ * (`https://answerloops.com`). Point this at a self-hosted instance instead.
67
+ */
68
+ baseUrl?: string;
69
+ /** Overrides the global `fetch` — mainly for tests. */
70
+ fetch?: typeof fetch;
71
+ }
72
+ declare class AgentApiError extends Error {
73
+ readonly status: number;
74
+ readonly body: AgentApiErrorBody | undefined;
75
+ constructor(status: number, body: AgentApiErrorBody | undefined, message: string);
76
+ }
77
+ declare class AgentClient {
78
+ private readonly apiKey;
79
+ private readonly baseUrl;
80
+ private readonly fetchImpl;
81
+ constructor(options: AgentClientOptions);
82
+ /** GET /api/agent/kb/search — requires the `kb:read` scope. */
83
+ searchKb(params: SearchKbParams): Promise<KbSearchResponse>;
84
+ /** GET /api/agent/faq — requires the `faq:read` scope. */
85
+ getFaq(): Promise<unknown>;
86
+ /** GET /api/agent/tickets — requires the `tickets:read` scope. */
87
+ getTickets(params?: GetTicketsParams): Promise<GetTicketsResponse>;
88
+ /** POST /api/agent/tickets — requires the `tickets:write` scope. */
89
+ createTicket(params: CreateTicketParams): Promise<Ticket>;
90
+ /** POST /api/agent/answers — requires the `answers:write` scope. */
91
+ generateAnswer(params: GenerateAnswerParams): Promise<GenerateAnswerResponse>;
92
+ private request;
93
+ }
94
+
95
+ export { AgentApiError, type AgentApiErrorBody, AgentClient, type AgentClientOptions, type CreateTicketParams, type GenerateAnswerParams, type GenerateAnswerResponse, type GetTicketsParams, type GetTicketsResponse, type KbSearchResponse, type KbSearchResult, type SearchKbParams, type Ticket, type TicketCategory, type TicketPriority, type TicketStatus };
package/dist/index.js ADDED
@@ -0,0 +1,81 @@
1
+ // src/client.ts
2
+ var AgentApiError = class extends Error {
3
+ status;
4
+ body;
5
+ constructor(status, body, message) {
6
+ super(message);
7
+ this.name = "AgentApiError";
8
+ this.status = status;
9
+ this.body = body;
10
+ }
11
+ };
12
+ var DEFAULT_BASE_URL = "https://answerloops.com";
13
+ var AgentClient = class {
14
+ apiKey;
15
+ baseUrl;
16
+ fetchImpl;
17
+ constructor(options) {
18
+ if (!options.apiKey) {
19
+ throw new Error("AgentClient requires an apiKey (Settings -> API Keys).");
20
+ }
21
+ this.apiKey = options.apiKey;
22
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
23
+ this.fetchImpl = options.fetch ?? fetch;
24
+ }
25
+ /** GET /api/agent/kb/search — requires the `kb:read` scope. */
26
+ searchKb(params) {
27
+ const query = new URLSearchParams({ query: params.query });
28
+ if (params.limit !== void 0) query.set("limit", String(params.limit));
29
+ return this.request("GET", `/api/agent/kb/search?${query}`);
30
+ }
31
+ /** GET /api/agent/faq — requires the `faq:read` scope. */
32
+ getFaq() {
33
+ return this.request("GET", "/api/agent/faq");
34
+ }
35
+ /** GET /api/agent/tickets — requires the `tickets:read` scope. */
36
+ getTickets(params = {}) {
37
+ const query = new URLSearchParams();
38
+ if (params.status) query.set("status", params.status);
39
+ if (params.priority) query.set("priority", params.priority);
40
+ if (params.category) query.set("category", params.category);
41
+ if (params.limit !== void 0) query.set("limit", String(params.limit));
42
+ const qs = query.toString();
43
+ return this.request("GET", `/api/agent/tickets${qs ? `?${qs}` : ""}`);
44
+ }
45
+ /** POST /api/agent/tickets — requires the `tickets:write` scope. */
46
+ createTicket(params) {
47
+ return this.request("POST", "/api/agent/tickets", {
48
+ content: params.content,
49
+ authorName: params.authorName,
50
+ idempotencyKey: params.idempotencyKey
51
+ });
52
+ }
53
+ /** POST /api/agent/answers — requires the `answers:write` scope. */
54
+ generateAnswer(params) {
55
+ return this.request("POST", "/api/agent/answers", { question: params.question });
56
+ }
57
+ async request(method, path, body) {
58
+ const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
59
+ method,
60
+ headers: {
61
+ Authorization: `Bearer ${this.apiKey}`,
62
+ ...body ? { "Content-Type": "application/json" } : {}
63
+ },
64
+ body: body ? JSON.stringify(body) : void 0
65
+ });
66
+ const text = await res.text();
67
+ const data = text ? JSON.parse(text) : void 0;
68
+ if (!res.ok) {
69
+ throw new AgentApiError(
70
+ res.status,
71
+ data,
72
+ data?.error ?? `Agent API request failed: ${res.status}`
73
+ );
74
+ }
75
+ return data;
76
+ }
77
+ };
78
+ export {
79
+ AgentApiError,
80
+ AgentClient
81
+ };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@answerloops/agent-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Typed client for the answerLoops Agent API (knowledge base search, FAQ, tickets, grounded answers).",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "sideEffects": false,
21
+ "publishConfig": {
22
+ "access": "public",
23
+ "provenance": true
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/answerLoops/answerLoops.git",
28
+ "directory": "packages/agent-sdk"
29
+ },
30
+ "homepage": "https://answerloops.com/docs/integrations/agent-api",
31
+ "bugs": "https://github.com/answerLoops/answerLoops/issues",
32
+ "keywords": [
33
+ "answerloops",
34
+ "agent-api",
35
+ "mcp",
36
+ "support",
37
+ "knowledge-base"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean",
41
+ "typecheck": "tsc --noEmit"
42
+ },
43
+ "devDependencies": {
44
+ "tsup": "^8.3.5",
45
+ "typescript": "^5.7.3"
46
+ },
47
+ "engines": {
48
+ "node": ">=18"
49
+ }
50
+ }