plugin-paperclip-personal-openia-adapter 0.0.0-stage → 0.1.1

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 CHANGED
@@ -1,3 +1,64 @@
1
- # Temporary Holding Version
1
+ # OpenAI‑compatible Adapter for Paperclip
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ![npm](https://img.shields.io/npm/v/plugin-paperclip-personal-openia-adapter)
4
+ ![npm downloads](https://img.shields.io/npm/dt/plugin-paperclip-personal-openia-adapter)
5
+
6
+ ---
7
+
8
+ <details open>
9
+ <summary>🇺🇸 English</summary>
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm i plugin-paperclip-personal-openia-adapter
15
+ ```
16
+
17
+ ## Configuration (Paperclip UI)
18
+
19
+ | Field | Label | Default value | Description |
20
+ |---------|------------------------------------|------------------------------|--------------------------------------------------------|
21
+ | `baseUrl` | Base URL of the OpenAI gateway | `https://api.openai.com/v1` | Base endpoint address (e.g., https://example.com/v1) |
22
+ | `apiKey` | API Key | – | Access key for the gateway (secret field) |
23
+ | `model` | Model name | `gpt-4o` | Identifier of the model to be used |
24
+
25
+ ## How it works
26
+
27
+ 1. Paperclip calls the `handleChat` function with the user's messages.
28
+ 2. The adapter constructs a **POST** request to `${baseUrl}/chat/completions`.
29
+ 3. The request includes the header `Authorization: Bearer <apiKey>`.
30
+ 4. The response returns the content of `choices[0].message.content`.
31
+ 5. In case of error, friendly messages are generated without mentioning specific providers.
32
+
33
+ ---
34
+ </details>
35
+
36
+ <details>
37
+ <summary>🇧🇷 Português</summary>
38
+
39
+ ## Instalação
40
+
41
+ ```bash
42
+ npm i plugin-paperclip-personal-openia-adapter
43
+ ```
44
+
45
+ ## Configuração (UI exibida no Paperclip)
46
+
47
+ | Campo | Rótulo | Valor padrão | Descrição |
48
+ |------------|----------------------|-----------------------------|------------------------------------------------------|
49
+ | `baseUrl` | Base URL do gateway OpenAI | `https://api.openai.com/v1` | Endereço base do endpoint (ex.: https://example.com/v1) |
50
+ | `apiKey` | API Key | – | Chave de acesso ao gateway (campo secreto) |
51
+ | `model` | Nome do Modelo | `gpt-4o` | Identificador do modelo a ser usado |
52
+
53
+ ## Como funciona
54
+
55
+ 1. O Paperclip chama a função `handleChat` passando as mensagens do usuário.
56
+ 2. O adapter monta a requisição **POST** para `${baseUrl}/chat/completions`.
57
+ 3. A requisição inclui o cabeçalho `Authorization: Bearer <apiKey>`.
58
+ 4. A resposta é retornada como o conteúdo de `choices[0].message.content`.
59
+ 5. Em caso de erro, mensagens amigáveis são geradas sem citar provedores específicos.
60
+
61
+ ---
62
+ </details>
63
+
64
+ MIT © 2026 Glebson Santos
@@ -0,0 +1,18 @@
1
+ /**
2
+ * External Adapter – OpenAI compatible (e.g., 9route)
3
+ *
4
+ * Implements the Paperclip SDK contract. The adapter is generic for any
5
+ * OpenAI‑compatible endpoint, therefore error messages refer only to the
6
+ * generic gateway and not to a specific provider such as "9route".
7
+ */
8
+ import { Adapter, ConfigField } from '@paperclip/sdk';
9
+ /** ------------------------------------------------------------
10
+ * 1️⃣ CONFIGURATION SCHEMA (UI displayed in Paperclip)
11
+ * ------------------------------------------------------------ */
12
+ export declare const configSchema: ConfigField[];
13
+ /** ------------------------------------------------------------
14
+ * 3️⃣ EXPORT ADAPTER OBJECT
15
+ * ------------------------------------------------------------ */
16
+ export declare const adapter: Adapter;
17
+ export default adapter;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EACL,OAAO,EAIP,WAAW,EACZ,MAAM,gBAAgB,CAAC;AAExB;;kEAEkE;AAClE,eAAO,MAAM,YAAY,EAAE,WAAW,EAyBrC,CAAC;AAyDF;;kEAEkE;AAClE,eAAO,MAAM,OAAO,EAAE,OAIrB,CAAC;AAEF,eAAe,OAAO,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ /**
3
+ * External Adapter – OpenAI compatible (e.g., 9route)
4
+ *
5
+ * Implements the Paperclip SDK contract. The adapter is generic for any
6
+ * OpenAI‑compatible endpoint, therefore error messages refer only to the
7
+ * generic gateway and not to a specific provider such as "9route".
8
+ */
9
+ var __importDefault = (this && this.__importDefault) || function (mod) {
10
+ return (mod && mod.__esModule) ? mod : { "default": mod };
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.adapter = exports.configSchema = void 0;
14
+ const axios_1 = __importDefault(require("axios"));
15
+ /** ------------------------------------------------------------
16
+ * 1️⃣ CONFIGURATION SCHEMA (UI displayed in Paperclip)
17
+ * ------------------------------------------------------------ */
18
+ exports.configSchema = [
19
+ {
20
+ key: 'baseUrl',
21
+ type: 'string',
22
+ label: 'Base URL do gateway OpenAI',
23
+ default: 'https://api.openai.com/v1',
24
+ placeholder: 'https://example.com/v1',
25
+ description: 'Endereço base do gateway compatível com a API da OpenAI.',
26
+ },
27
+ {
28
+ key: 'apiKey',
29
+ type: 'string',
30
+ label: 'API Key',
31
+ secret: true,
32
+ placeholder: 'sk-*****',
33
+ description: 'Chave de acesso ao gateway.',
34
+ },
35
+ {
36
+ key: 'model',
37
+ type: 'string',
38
+ label: 'Nome do Modelo',
39
+ default: 'gpt-4o',
40
+ placeholder: 'gpt-4o',
41
+ description: 'Identificador do modelo a ser usado.',
42
+ },
43
+ ];
44
+ /** ------------------------------------------------------------
45
+ * 2️⃣ CHAT REQUEST HANDLER
46
+ * ------------------------------------------------------------ */
47
+ async function handleChat(config, request) {
48
+ // Ensure the base URL does not end with a slash before appending the path
49
+ const url = `${config.baseUrl?.replace(/\/+$/, '')}/chat/completions`;
50
+ const payload = {
51
+ model: config.model ?? 'gpt-4o',
52
+ messages: request.messages,
53
+ temperature: request.options?.temperature ?? 0.7,
54
+ top_p: request.options?.top_p ?? 1,
55
+ };
56
+ try {
57
+ const resp = await axios_1.default.post(url, payload, {
58
+ headers: {
59
+ 'Content-Type': 'application/json',
60
+ Authorization: `Bearer ${config.apiKey}`,
61
+ },
62
+ timeout: 30_000,
63
+ });
64
+ const choice = resp.data?.choices?.[0];
65
+ if (!choice?.message?.content) {
66
+ throw new Error('Resposta inesperada da API OpenAI‑compatible.');
67
+ }
68
+ return { content: choice.message.content };
69
+ }
70
+ catch (err) {
71
+ // -------- Friendly generic error handling --------
72
+ if (axios_1.default.isAxiosError(err)) {
73
+ const axiosErr = err;
74
+ const status = axiosErr.response?.status;
75
+ const data = axiosErr.response?.data;
76
+ let friendlyMsg = 'Erro ao comunicar com o gateway OpenAI‑compatible.';
77
+ if (status === 401)
78
+ friendlyMsg = 'Credenciais inválidas (401).';
79
+ else if (status === 404)
80
+ friendlyMsg = 'Endpoint não encontrado (404).';
81
+ else if (status && status >= 500)
82
+ friendlyMsg = 'Erro interno do servidor (5xx).';
83
+ else if (data && typeof data === 'object' && 'error' in data) {
84
+ // OpenAI‑style error payload
85
+ friendlyMsg = `Gateway error: ${data.error?.message ?? friendlyMsg}`;
86
+ }
87
+ throw new Error(friendlyMsg);
88
+ }
89
+ // Non‑HTTP errors
90
+ throw err;
91
+ }
92
+ }
93
+ /** ------------------------------------------------------------
94
+ * 3️⃣ EXPORT ADAPTER OBJECT
95
+ * ------------------------------------------------------------ */
96
+ exports.adapter = {
97
+ name: 'OpenAI‑compatible Adapter (personal)',
98
+ configSchema: exports.configSchema,
99
+ handleChat,
100
+ };
101
+ exports.default = exports.adapter;
102
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,30 @@
1
1
  {
2
2
  "name": "plugin-paperclip-personal-openia-adapter",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.1",
4
+ "description": "External adapter for Paperclip AI that connects to an OpenAI‑compatible gateway (e.g., 9route).",
5
+ "author": "Glebson Santos <glebsonsantos@outlook.pt>",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist",
11
+ "src",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "clean": "rm -rf dist",
16
+ "build": "tsc",
17
+ "prepare": "npm run clean && npm run build"
18
+ },
19
+ "dependencies": {
20
+ "axios": "^1.7.2"
21
+ },
22
+ "peerDependencies": {
23
+ "@paperclip/sdk": "^1.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@paperclip/sdk": "file:./sdk",
27
+ "typescript": "^5.5.4",
28
+ "rimraf": "^5.0.5"
29
+ }
30
+ }
package/src/index.ts ADDED
@@ -0,0 +1,112 @@
1
+ /**
2
+ * External Adapter – OpenAI compatible (e.g., 9route)
3
+ *
4
+ * Implements the Paperclip SDK contract. The adapter is generic for any
5
+ * OpenAI‑compatible endpoint, therefore error messages refer only to the
6
+ * generic gateway and not to a specific provider such as "9route".
7
+ */
8
+
9
+ import axios, { AxiosError } from 'axios';
10
+ import {
11
+ Adapter,
12
+ AdapterConfig,
13
+ ChatRequest,
14
+ ChatResponse,
15
+ ConfigField,
16
+ } from '@paperclip/sdk';
17
+
18
+ /** ------------------------------------------------------------
19
+ * 1️⃣ CONFIGURATION SCHEMA (UI displayed in Paperclip)
20
+ * ------------------------------------------------------------ */
21
+ export const configSchema: ConfigField[] = [
22
+ {
23
+ key: 'baseUrl',
24
+ type: 'string',
25
+ label: 'Base URL do gateway OpenAI',
26
+ default: 'https://api.openai.com/v1',
27
+ placeholder: 'https://example.com/v1',
28
+ description: 'Endereço base do gateway compatível com a API da OpenAI.',
29
+ },
30
+ {
31
+ key: 'apiKey',
32
+ type: 'string',
33
+ label: 'API Key',
34
+ secret: true,
35
+ placeholder: 'sk-*****',
36
+ description: 'Chave de acesso ao gateway.',
37
+ },
38
+ {
39
+ key: 'model',
40
+ type: 'string',
41
+ label: 'Nome do Modelo',
42
+ default: 'gpt-4o',
43
+ placeholder: 'gpt-4o',
44
+ description: 'Identificador do modelo a ser usado.',
45
+ },
46
+ ];
47
+
48
+ /** ------------------------------------------------------------
49
+ * 2️⃣ CHAT REQUEST HANDLER
50
+ * ------------------------------------------------------------ */
51
+ async function handleChat(
52
+ config: AdapterConfig,
53
+ request: ChatRequest
54
+ ): Promise<ChatResponse> {
55
+ // Ensure the base URL does not end with a slash before appending the path
56
+ const url = `${config.baseUrl?.replace(/\/+$/, '')}/chat/completions`;
57
+
58
+ const payload = {
59
+ model: config.model ?? 'gpt-4o',
60
+ messages: request.messages,
61
+ temperature: request.options?.temperature ?? 0.7,
62
+ top_p: request.options?.top_p ?? 1,
63
+ };
64
+
65
+ try {
66
+ const resp = await axios.post(url, payload, {
67
+ headers: {
68
+ 'Content-Type': 'application/json',
69
+ Authorization: `Bearer ${config.apiKey}`,
70
+ },
71
+ timeout: 30_000,
72
+ });
73
+
74
+ const choice = resp.data?.choices?.[0];
75
+ if (!choice?.message?.content) {
76
+ throw new Error('Resposta inesperada da API OpenAI‑compatible.');
77
+ }
78
+
79
+ return { content: choice.message.content } as ChatResponse;
80
+ } catch (err) {
81
+ // -------- Friendly generic error handling --------
82
+ if (axios.isAxiosError(err)) {
83
+ const axiosErr = err as AxiosError;
84
+ const status = axiosErr.response?.status;
85
+ const data = axiosErr.response?.data;
86
+
87
+ let friendlyMsg = 'Erro ao comunicar com o gateway OpenAI‑compatible.';
88
+ if (status === 401) friendlyMsg = 'Credenciais inválidas (401).';
89
+ else if (status === 404) friendlyMsg = 'Endpoint não encontrado (404).';
90
+ else if (status && status >= 500) friendlyMsg = 'Erro interno do servidor (5xx).';
91
+ else if (data && typeof data === 'object' && 'error' in data) {
92
+ // OpenAI‑style error payload
93
+ friendlyMsg = `Gateway error: ${(data as any).error?.message ?? friendlyMsg}`;
94
+ }
95
+
96
+ throw new Error(friendlyMsg);
97
+ }
98
+ // Non‑HTTP errors
99
+ throw err;
100
+ }
101
+ }
102
+
103
+ /** ------------------------------------------------------------
104
+ * 3️⃣ EXPORT ADAPTER OBJECT
105
+ * ------------------------------------------------------------ */
106
+ export const adapter: Adapter = {
107
+ name: 'OpenAI‑compatible Adapter (personal)',
108
+ configSchema,
109
+ handleChat,
110
+ };
111
+
112
+ export default adapter;