mirror of
https://github.com/numexai/numex-sdk.git
synced 2026-09-25 13:32:15 +00:00
Numex SDK: acik kaynak ilk surum (v1.1.0)
This commit is contained in:
parent
58b650ce4b
commit
0d263a3f94
17
.github/workflows/test.yml
vendored
Normal file
17
.github/workflows/test.yml
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
name: test
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node: [18, 20, 22]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node }}
|
||||||
|
- run: npm test
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
node_modules/
|
||||||
|
.env*
|
||||||
|
*.log
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025-2026 Numex AI Bilişim Teknolojileri
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
BIN
assets/numex-banner.png
Normal file
BIN
assets/numex-banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 204 KiB |
50
package.json
Normal file
50
package.json
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
{
|
||||||
|
"name": "numexcodex-sdk",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"description": "Official Node.js / TypeScript SDK for the Numex AI API and the Numex CLI — Türkçe yapay zekâ SDK'sı.",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"types": "src/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./src/index.mjs",
|
||||||
|
"require": "./src/index.js",
|
||||||
|
"types": "./src/index.d.ts"
|
||||||
|
},
|
||||||
|
"./package.json": "./package.json"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/",
|
||||||
|
"package.json",
|
||||||
|
"README.md",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"test": "node test/test.js && node test/cli-integration.test.js && node test/agentic-e2e.test.js"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"numex",
|
||||||
|
"numex-ai",
|
||||||
|
"ai",
|
||||||
|
"llm",
|
||||||
|
"sdk",
|
||||||
|
"api",
|
||||||
|
"cli",
|
||||||
|
"agent",
|
||||||
|
"turkish",
|
||||||
|
"turkce",
|
||||||
|
"yapay-zeka"
|
||||||
|
],
|
||||||
|
"author": "Numex AI Bilişim Teknolojileri <destek@numexai.com.tr>",
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "https://github.com/mobilcep/numex-sdk#readme",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/mobilcep/numex-sdk.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/mobilcep/numex-sdk/issues"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
}
|
||||||
147
src/bridge.js
Normal file
147
src/bridge.js
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean helper to extract the last valid JSON object or array from stdout string
|
||||||
|
*/
|
||||||
|
function parseLastJson(stdout) {
|
||||||
|
if (!stdout || typeof stdout !== 'string') return null;
|
||||||
|
const clean = stdout.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
|
||||||
|
const lines = clean.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
||||||
|
|
||||||
|
for (let i = lines.length - 1; i >= 0; i--) {
|
||||||
|
const line = lines[i];
|
||||||
|
if ((line.startsWith('{') && line.endsWith('}')) || (line.startsWith('[') && line.endsWith(']'))) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(line);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Programmatic CLI bridge for Numex CLI execution.
|
||||||
|
*/
|
||||||
|
class NumexBridge {
|
||||||
|
constructor(options = {}) {
|
||||||
|
this._command = options.command || 'numex';
|
||||||
|
this._getCwd = options.getCwd || (() => process.cwd());
|
||||||
|
this._shell = options.shell === true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes CLI command with arguments and returns structured result object.
|
||||||
|
* @param {Array<string>} [args=[]] - Arguments to pass to CLI
|
||||||
|
* @param {Object} [options={}] - Options for execution
|
||||||
|
* @param {string} [options.cwd] - Custom working directory
|
||||||
|
* @param {Object} [options.env] - Custom environment variables
|
||||||
|
* @param {number} [options.timeout] - Timeout in milliseconds
|
||||||
|
* @returns {Promise<{success: boolean, stdout: string, stderr: string, code: number|null, data?: any, error?: string}>}
|
||||||
|
*/
|
||||||
|
run(args = [], options = {}) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const command = options.command || this._command;
|
||||||
|
const cwd = options.cwd || (this._getCwd ? this._getCwd() : process.cwd());
|
||||||
|
const env = options.env ? { ...process.env, ...options.env } : process.env;
|
||||||
|
const shell = options.shell !== undefined ? options.shell : this._shell;
|
||||||
|
const timeout = typeof options.timeout === 'number' && options.timeout > 0 ? options.timeout : null;
|
||||||
|
|
||||||
|
let proc;
|
||||||
|
let timer = null;
|
||||||
|
let killedByTimeout = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
proc = spawn(command, Array.isArray(args) ? args : [args], { cwd, env, shell });
|
||||||
|
} catch (err) {
|
||||||
|
return resolve({
|
||||||
|
success: false,
|
||||||
|
stdout: '',
|
||||||
|
stderr: '',
|
||||||
|
code: null,
|
||||||
|
error: err.message || 'CLI süreci başlatılamadı.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let stdout = '';
|
||||||
|
let stderr = '';
|
||||||
|
|
||||||
|
if (timeout) {
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
killedByTimeout = true;
|
||||||
|
try {
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
spawn('taskkill', ['/pid', String(proc.pid), '/T', '/F'], { stdio: 'ignore' });
|
||||||
|
} else {
|
||||||
|
proc.kill('SIGKILL');
|
||||||
|
}
|
||||||
|
} catch (_) {
|
||||||
|
try { proc.kill(); } catch (_) {}
|
||||||
|
}
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proc.stdout) {
|
||||||
|
proc.stdout.on('data', (d) => { stdout += d.toString(); });
|
||||||
|
}
|
||||||
|
if (proc.stderr) {
|
||||||
|
proc.stderr.on('data', (d) => { stderr += d.toString(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
proc.on('error', (err) => {
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
resolve({
|
||||||
|
success: false,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
code: null,
|
||||||
|
error: err.message || 'CLI yürütme hatası'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
proc.on('close', (code) => {
|
||||||
|
if (timer) clearTimeout(timer);
|
||||||
|
|
||||||
|
if (killedByTimeout) {
|
||||||
|
return resolve({
|
||||||
|
success: false,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
code: null,
|
||||||
|
error: `CLI komutu zaman aşımına uğradı (${timeout}ms)`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code !== 0 && code !== null) {
|
||||||
|
return resolve({
|
||||||
|
success: false,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
code,
|
||||||
|
error: stderr.trim() || `CLI komutu ${code} çıkış kodu ile sonlandı.`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedData = parseLastJson(stdout);
|
||||||
|
const data = parsedData !== null ? parsedData : stdout.trim();
|
||||||
|
|
||||||
|
resolve({
|
||||||
|
success: true,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
code: 0,
|
||||||
|
data
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for simple JSON output retrieval
|
||||||
|
*/
|
||||||
|
async runJson(args = [], options = {}) {
|
||||||
|
const res = await this.run(args, options);
|
||||||
|
return res.success ? res.data : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { NumexBridge, parseLastJson };
|
||||||
107
src/index.d.ts
vendored
Normal file
107
src/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
export interface NumexOptions {
|
||||||
|
apiKey?: string;
|
||||||
|
baseURL?: string;
|
||||||
|
/** Node executable path (e.g. process.execPath) or CLI command name (e.g. 'numex') */
|
||||||
|
command?: string;
|
||||||
|
cwd?: string;
|
||||||
|
requireApiKey?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NumexBridgeOptions {
|
||||||
|
/** Node executable path (e.g. process.execPath) or CLI command name (e.g. 'numex') */
|
||||||
|
command?: string;
|
||||||
|
getCwd?: () => string;
|
||||||
|
shell?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NumexBridgeRunOptions {
|
||||||
|
cwd?: string;
|
||||||
|
env?: Record<string, string>;
|
||||||
|
timeout?: number;
|
||||||
|
command?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NumexBridgeResult {
|
||||||
|
success: boolean;
|
||||||
|
stdout: string;
|
||||||
|
stderr: string;
|
||||||
|
code: number | null;
|
||||||
|
data?: any;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NumexBridge {
|
||||||
|
constructor(options?: NumexBridgeOptions);
|
||||||
|
run(args?: string[], options?: NumexBridgeRunOptions): Promise<NumexBridgeResult>;
|
||||||
|
runJson(args?: string[], options?: NumexBridgeRunOptions): Promise<any | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChatMessage {
|
||||||
|
role: 'system' | 'user' | 'assistant';
|
||||||
|
content: string | any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChatCompletionRequest {
|
||||||
|
messages: ChatMessage[];
|
||||||
|
model?: string;
|
||||||
|
stream?: boolean;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChatCompletions {
|
||||||
|
create(params: ChatCompletionRequest): Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Chat {
|
||||||
|
completions: ChatCompletions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Images {
|
||||||
|
generate(params: {
|
||||||
|
prompt: string;
|
||||||
|
n?: number;
|
||||||
|
size?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}): Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Embeddings {
|
||||||
|
create(params: {
|
||||||
|
input: string | string[];
|
||||||
|
model?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}): Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Models {
|
||||||
|
list(): Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Search {
|
||||||
|
query(params: {
|
||||||
|
query: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}): Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NumexApiClient {
|
||||||
|
constructor(baseURL: string, apiKey?: string);
|
||||||
|
post(path: string, data?: any, options?: any): Promise<any>;
|
||||||
|
get(path: string, options?: any): Promise<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Numex {
|
||||||
|
constructor(options?: NumexOptions);
|
||||||
|
apiKey?: string;
|
||||||
|
baseURL: string;
|
||||||
|
client: NumexApiClient;
|
||||||
|
cli: NumexBridge;
|
||||||
|
chat: Chat;
|
||||||
|
images: Images;
|
||||||
|
embeddings: Embeddings;
|
||||||
|
models: Models;
|
||||||
|
search: Search;
|
||||||
|
run(command: string | string[], args?: string[] | Record<string, any>, options?: NumexBridgeRunOptions): Promise<NumexBridgeResult>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Numex;
|
||||||
119
src/index.js
Normal file
119
src/index.js
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
const Chat = require('./resources/chat');
|
||||||
|
const Images = require('./resources/images');
|
||||||
|
const Embeddings = require('./resources/embeddings');
|
||||||
|
const Models = require('./resources/models');
|
||||||
|
const Search = require('./resources/search');
|
||||||
|
const { NumexBridge } = require('./bridge');
|
||||||
|
|
||||||
|
class NumexApiClient {
|
||||||
|
constructor(baseURL, apiKey) {
|
||||||
|
this.baseURL = baseURL;
|
||||||
|
this.apiKey = apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _request(path, options = {}) {
|
||||||
|
const url = `${this.baseURL}${path}`;
|
||||||
|
const headers = {
|
||||||
|
'Authorization': `Bearer ${this.apiKey}`,
|
||||||
|
'User-Agent': 'numex-node-sdk/1.1.0',
|
||||||
|
...(options.headers || {})
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.body && typeof options.body === 'object') {
|
||||||
|
options.body = JSON.stringify(options.body);
|
||||||
|
headers['Content-Type'] = 'application/json';
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(url, { ...options, headers });
|
||||||
|
|
||||||
|
// Handle stream response
|
||||||
|
if (options.stream) {
|
||||||
|
if (!res.ok) {
|
||||||
|
const errText = await res.text();
|
||||||
|
throw new Error(`Numex API Error [${res.status}]: ${errText}`);
|
||||||
|
}
|
||||||
|
return res.body; // Return the ReadableStream
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle normal JSON response
|
||||||
|
const data = await res.json().catch(() => ({}));
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`Numex API Error [${res.status}]: ${data.error ? JSON.stringify(data.error) : JSON.stringify(data)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
post(path, data, options = {}) {
|
||||||
|
return this._request(path, { method: 'POST', body: data, ...options });
|
||||||
|
}
|
||||||
|
|
||||||
|
get(path, options = {}) {
|
||||||
|
return this._request(path, { method: 'GET', ...options });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Numex {
|
||||||
|
/**
|
||||||
|
* Initialize the Numex API Client & CLI Bridge
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {string} [options.apiKey] - Your Numex Developer API Key
|
||||||
|
* @param {string} [options.baseURL] - Optional custom base URL
|
||||||
|
* @param {string} [options.command] - Optional custom CLI command name
|
||||||
|
* @param {string} [options.cwd] - Optional working directory
|
||||||
|
*/
|
||||||
|
constructor(options = {}) {
|
||||||
|
this.apiKey = options.apiKey || process.env.NUMEX_API_KEY;
|
||||||
|
if (!this.apiKey && options.requireApiKey !== false) {
|
||||||
|
throw new Error("Numex API Key is required. Pass it via options or set NUMEX_API_KEY environment variable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.baseURL = options.baseURL || 'https://api.numexai.com.tr/v1';
|
||||||
|
this.client = new NumexApiClient(this.baseURL, this.apiKey);
|
||||||
|
|
||||||
|
// CLI Bridge for programmatic CLI execution
|
||||||
|
this.cli = new NumexBridge({
|
||||||
|
command: options.command || 'numex',
|
||||||
|
getCwd: () => options.cwd || process.cwd()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sub-modules
|
||||||
|
this.chat = new Chat(this.client);
|
||||||
|
this.images = new Images(this.client);
|
||||||
|
this.embeddings = new Embeddings(this.client);
|
||||||
|
this.models = new Models(this.client);
|
||||||
|
this.search = new Search(this.client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run programmatic CLI command
|
||||||
|
* @param {string|Array<string>} command - CLI subcommand or array of arguments
|
||||||
|
* @param {Array<string>|Object} [args=[]] - Additional arguments or options if args omitted
|
||||||
|
* @param {Object} [options={}] - Options like timeout, cwd, env
|
||||||
|
* @example await numex.run('coklu_duzenle', ['src/'], { timeout: 60000 })
|
||||||
|
*/
|
||||||
|
async run(command, args = [], options = {}) {
|
||||||
|
let fullArgs = [];
|
||||||
|
|
||||||
|
if (Array.isArray(command)) {
|
||||||
|
fullArgs = [...command];
|
||||||
|
if (typeof args === 'object' && !Array.isArray(args)) {
|
||||||
|
options = args;
|
||||||
|
} else if (Array.isArray(args)) {
|
||||||
|
fullArgs.push(...args);
|
||||||
|
}
|
||||||
|
} else if (typeof command === 'string') {
|
||||||
|
fullArgs = [command];
|
||||||
|
if (typeof args === 'object' && !Array.isArray(args)) {
|
||||||
|
options = args;
|
||||||
|
} else if (Array.isArray(args)) {
|
||||||
|
fullArgs.push(...args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.cli.run(fullArgs, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { Numex, NumexApiClient, NumexBridge };
|
||||||
7
src/index.mjs
Normal file
7
src/index.mjs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { createRequire } from 'node:module';
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url);
|
||||||
|
const { Numex, NumexBridge, NumexApiClient } = require('./index.js');
|
||||||
|
|
||||||
|
export { Numex, NumexBridge, NumexApiClient };
|
||||||
|
export default Numex;
|
||||||
21
src/resources/chat.js
Normal file
21
src/resources/chat.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
class ChatCompletions {
|
||||||
|
constructor(client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(params) {
|
||||||
|
// If stream is requested, use the appropriate streaming endpoint/method
|
||||||
|
if (params.stream) {
|
||||||
|
return this.client.post('/chat/stream', params, { stream: true });
|
||||||
|
}
|
||||||
|
return this.client.post('/chat', params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Chat {
|
||||||
|
constructor(client) {
|
||||||
|
this.completions = new ChatCompletions(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Chat;
|
||||||
11
src/resources/embeddings.js
Normal file
11
src/resources/embeddings.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
class Embeddings {
|
||||||
|
constructor(client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(params) {
|
||||||
|
return this.client.post('/embeddings', params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Embeddings;
|
||||||
11
src/resources/images.js
Normal file
11
src/resources/images.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
class Images {
|
||||||
|
constructor(client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
async generate(params) {
|
||||||
|
return this.client.post('/images/generations', params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Images;
|
||||||
11
src/resources/models.js
Normal file
11
src/resources/models.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
class Models {
|
||||||
|
constructor(client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
async list() {
|
||||||
|
return this.client.get('/models');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Models;
|
||||||
11
src/resources/search.js
Normal file
11
src/resources/search.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
class Search {
|
||||||
|
constructor(client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
async query(params) {
|
||||||
|
return this.client.post('/search', params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Search;
|
||||||
51
test/agentic-e2e.test.js
Normal file
51
test/agentic-e2e.test.js
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
const assert = require('assert');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { Numex } = require('../src/index');
|
||||||
|
|
||||||
|
async function testAgenticE2E() {
|
||||||
|
console.log('🧪 Numex SDK → CLI → @numex/core Agentic Zincir Testi...\n');
|
||||||
|
|
||||||
|
const cliPath = path.resolve(__dirname, '../../numex-cli/bin/numex.js');
|
||||||
|
const projectRoot = path.resolve(__dirname, '../..');
|
||||||
|
|
||||||
|
if (!fs.existsSync(cliPath)) {
|
||||||
|
console.log('⚠️ SKIP: numex CLI bulunamadı (' + cliPath + ')');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const numex = new Numex({
|
||||||
|
requireApiKey: false,
|
||||||
|
command: process.execPath
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1) numex.run() ile 'guard' (Commit Risk Taraması - @numex/core/commitGuard.js)
|
||||||
|
console.log('1) SDK üzerinden numex.run("guard", ["--json"]) tetikleniyor...');
|
||||||
|
const guardRes = await numex.run([cliPath, 'guard', '--json'], { cwd: projectRoot, timeout: 15000 });
|
||||||
|
|
||||||
|
console.log(' Çıkış Kodu:', guardRes.code);
|
||||||
|
console.log(' Success:', guardRes.success);
|
||||||
|
console.log(' Ayrıştırılan Data:\n', JSON.stringify(guardRes.data, null, 2));
|
||||||
|
|
||||||
|
assert.strictEqual(guardRes.success, true, 'Guard komutu başarılı olmalı');
|
||||||
|
assert.ok(guardRes.data && typeof guardRes.data === 'object', 'Guard çıktısı JSON nesnesi olarak parse edilmeli');
|
||||||
|
assert.ok('risk' in guardRes.data || 'ok' in guardRes.data, 'Guard verisi risk veya ok alanını içermeli');
|
||||||
|
|
||||||
|
// 2) numex.run() ile 'harita' (Proje Haritası Üretici - @numex/core/projectMapGen.js)
|
||||||
|
console.log('\n2) SDK üzerinden numex.run("harita", ["--dry"]) tetikleniyor...');
|
||||||
|
const mapRes = await numex.run([cliPath, 'harita', '--dry'], { cwd: projectRoot, timeout: 15000 });
|
||||||
|
|
||||||
|
console.log(' Çıkış Kodu:', mapRes.code);
|
||||||
|
console.log(' Success:', mapRes.success);
|
||||||
|
console.log(' Stdout İlk 250 Karakter:\n', mapRes.stdout.slice(0, 250));
|
||||||
|
|
||||||
|
assert.strictEqual(mapRes.success, true, 'Harita komutu başarılı olmalı');
|
||||||
|
assert.ok(mapRes.stdout.includes('PROJECT_MAP') || mapRes.stdout.includes('dry') || mapRes.stdout.includes('Numex'), 'Harita çıktısı üretilmeli');
|
||||||
|
|
||||||
|
console.log('\n🎉 Zincir Testi Başarılı: SDK (numex.run) → CLI (bin/numex.js) → @numex/core zinciri somut olarak doğrulandı!');
|
||||||
|
}
|
||||||
|
|
||||||
|
testAgenticE2E().catch((err) => {
|
||||||
|
console.error('❌ Agentic E2E testi başarısız:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
43
test/cli-integration.test.js
Normal file
43
test/cli-integration.test.js
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
const assert = require('assert');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const { NumexBridge } = require('../src/index');
|
||||||
|
|
||||||
|
async function testCliIntegration() {
|
||||||
|
console.log('🧪 Gerçek Numex CLI Entegrasyon Testi Başlatılıyor...\n');
|
||||||
|
|
||||||
|
// CLI yolunu belirle: c:/numexai/numexai/numex-cli/bin/numex.js
|
||||||
|
const cliPath = path.resolve(__dirname, '../../numex-cli/bin/numex.js');
|
||||||
|
|
||||||
|
if (!fs.existsSync(cliPath)) {
|
||||||
|
console.log('⚠️ SKIP: numex CLI bulunamadı (' + cliPath + ')');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('🔍 Bulunan CLI Giriş Noktası:', cliPath);
|
||||||
|
|
||||||
|
// Node.js ile bin/numex.js çalıştırmak için command = process.execPath ve args = [cliPath, '--help']
|
||||||
|
const bridge = new NumexBridge({
|
||||||
|
command: process.execPath
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await bridge.run([cliPath, '--help'], { timeout: 15000 });
|
||||||
|
|
||||||
|
if (!res.success && res.error && (res.error.includes('ENOENT') || res.error.includes('tanınmıyor'))) {
|
||||||
|
console.log('⚠️ SKIP: numex CLI bulunamadı veya çalıştırılamadı.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.strictEqual(res.success, true, `CLI çağrısı başarılı olmalı (Hata: ${res.error})`);
|
||||||
|
assert.ok(
|
||||||
|
res.stdout.includes('Kullanım:') || res.stdout.includes('numex') || res.stdout.includes('Numex'),
|
||||||
|
'stdout içerisinde yardım veya Numex metni geçmeli'
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('✅ Gerçek Numex CLI entegrasyon testi başarıyla geçti!');
|
||||||
|
}
|
||||||
|
|
||||||
|
testCliIntegration().catch((err) => {
|
||||||
|
console.error('❌ CLI Entegrasyon testi başarısız:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
61
test/test.js
Normal file
61
test/test.js
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
const assert = require('assert');
|
||||||
|
const { Numex, NumexBridge } = require('../src/index');
|
||||||
|
|
||||||
|
async function runTests() {
|
||||||
|
console.log('🧪 Numex SDK & CLI Bridge Testleri Başlatılıyor...\n');
|
||||||
|
|
||||||
|
// Test 1: Numex Initialization & Sub-modules
|
||||||
|
const numex = new Numex({ apiKey: 'test_key_123' });
|
||||||
|
|
||||||
|
assert.ok(numex.chat, 'Chat modülü mevcut olmalı');
|
||||||
|
assert.ok(numex.images, 'Images modülü mevcut olmalı');
|
||||||
|
assert.ok(numex.embeddings, 'Embeddings modülü mevcut olmalı');
|
||||||
|
assert.ok(numex.models, 'Models modülü mevcut olmalı');
|
||||||
|
assert.ok(numex.search, 'Search modülü mevcut olmalı');
|
||||||
|
assert.ok(numex.cli, 'CLI bridge nesnesi mevcut olmalı');
|
||||||
|
assert.strictEqual(typeof numex.run, 'function', 'numex.run metodu fonksiyon olmalı');
|
||||||
|
|
||||||
|
console.log('✅ Test 1: Numex SDK başarıyla başlatıldı ve modüller doğrulandı.');
|
||||||
|
|
||||||
|
// Test 2: Numex.run metodu ve komut yapılandırma testi
|
||||||
|
assert.strictEqual(typeof numex.run, 'function', 'numex.run metodu mevcut olmalı');
|
||||||
|
|
||||||
|
// mock CLI bridge kullanarak run metodunu test edelim
|
||||||
|
const mockBridge = new NumexBridge({ command: process.execPath });
|
||||||
|
const nodeVersionResult = await mockBridge.run(['-v']);
|
||||||
|
assert.strictEqual(nodeVersionResult.success, true, 'Node -v komutu başarılı olmalı');
|
||||||
|
assert.ok(nodeVersionResult.stdout.includes('v'), 'stdout Node sürümünü içermeli');
|
||||||
|
|
||||||
|
console.log('✅ Test 2: numex.run metodu ve NumexBridge programatik çalıştırma doğrulandı.');
|
||||||
|
|
||||||
|
// Test 3: NumexBridge doğrudan nesne testi ve JSON parse testi
|
||||||
|
const customBridge = new NumexBridge({ command: process.execPath });
|
||||||
|
const jsonTestResult = await customBridge.run([
|
||||||
|
'-e',
|
||||||
|
'console.log("some log"); console.log(JSON.stringify({ status: "ok", count: 42 }));'
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.strictEqual(jsonTestResult.success, true, 'Custom bridge çalıştırma başarılı olmalı');
|
||||||
|
assert.deepStrictEqual(jsonTestResult.data, { status: 'ok', count: 42 }, 'Son JSON çıktısı başarıyla parse edilmeli');
|
||||||
|
|
||||||
|
console.log('✅ Test 3: NumexBridge doğrudan testi ve otomatik JSON ayrıştırma doğrulandı.');
|
||||||
|
|
||||||
|
// Test 4: Hata ve Zaman Aşımı Yönetimi (Error & Timeout Handling)
|
||||||
|
const timeoutBridge = new NumexBridge({ command: process.execPath });
|
||||||
|
const timeoutResult = await timeoutBridge.run(
|
||||||
|
['-e', 'setTimeout(() => {}, 10000);'],
|
||||||
|
{ timeout: 300 }
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.strictEqual(timeoutResult.success, false, 'Zaman aşımı sonrası success: false dönmeli');
|
||||||
|
assert.ok(timeoutResult.error.includes('zaman aşımı'), 'Hata mesajı zaman aşımını belirtmeli');
|
||||||
|
|
||||||
|
console.log('✅ Test 4: Güvenli hata ve zaman aşımı (timeout) yönetimi doğrulandı.');
|
||||||
|
|
||||||
|
console.log('\n🎉 TÜM TESTLER BAŞARIYLA TAMAMLANDI!');
|
||||||
|
}
|
||||||
|
|
||||||
|
runTests().catch((err) => {
|
||||||
|
console.error('❌ Test başarısız:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user