Skip to content

Commit 5d6c37c

Browse files
authored
Merge pull request #5 from OpenGradient/claude/add-ts-chat-completions-ZkER1
Mirror chat/completions from Python SDK; drop ML inference
2 parents d5c7a15 + e8b86ed commit 5d6c37c

19 files changed

Lines changed: 12092 additions & 8427 deletions

.github/workflows/ci.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
ci:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
node-version: [18.x, 20.x]
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Use Node.js ${{ matrix.node-version }}
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: ${{ matrix.node-version }}
22+
cache: npm
23+
24+
- run: npm ci
25+
26+
- run: npm run lint
27+
28+
- run: npm test
29+
30+
- run: npm run build

README.md

Lines changed: 102 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,123 @@
11
# OpenGradient TypeScript SDK
22

3-
A TypeScript/JavaScript SDK for performing on-chain inference using the OpenGradient network. Run machine learning models and LLMs directly on the blockchain with robust transaction handling and retry mechanisms.
3+
A TypeScript/JavaScript SDK for performing LLM chat and completion via OpenGradient's TEE (Trusted Execution Environment) with [x402](https://x402.org) payment protocol support.
44

55
## Installation
66

77
```bash
88
npm install opengradient-sdk
99
```
1010

11+
## Requirements
12+
13+
- Node.js 18+ (for global `fetch`)
14+
- A funded EVM wallet on Base (settlement happens in OPG on the Base network via [x402](https://x402.org))
15+
1116
## Quick Start
1217

1318
```typescript
14-
import { Client, InferenceMode, LLMInferenceMode } from 'opengradient-sdk';
19+
import { Client, TEE_LLM } from "opengradient-sdk";
1520

16-
// Initialize the client
1721
const client = new Client({
18-
privateKey: 'your-private-key'
22+
privateKey: process.env.PRIVATE_KEY!, // EVM private key (with or without 0x prefix)
23+
});
24+
25+
// Non-streaming chat
26+
const result = await client.llm.chat({
27+
model: TEE_LLM.CLAUDE_3_5_HAIKU,
28+
messages: [{ role: "user", content: "Hello!" }],
29+
maxTokens: 100,
30+
});
31+
console.log(result.chatOutput?.content);
32+
console.log("payment hash:", result.paymentHash);
33+
```
34+
35+
### Streaming chat
36+
37+
```typescript
38+
import { Client, TEE_LLM } from "opengradient-sdk";
39+
40+
const client = new Client({ privateKey: process.env.PRIVATE_KEY! });
41+
42+
const stream = client.llm.chat({
43+
model: TEE_LLM.CLAUDE_3_5_HAIKU,
44+
messages: [{ role: "user", content: "Stream me a haiku." }],
45+
stream: true,
46+
});
47+
48+
for await (const chunk of stream) {
49+
process.stdout.write(chunk.choices[0]?.delta.content ?? "");
50+
}
51+
```
52+
53+
### Tool / function calling
54+
55+
```typescript
56+
const result = await client.llm.chat({
57+
model: TEE_LLM.GPT_4O,
58+
messages: [{ role: "user", content: "What's the weather in Paris?" }],
59+
tools: [
60+
{
61+
type: "function",
62+
function: {
63+
name: "get_weather",
64+
description: "Get current weather for a city",
65+
parameters: {
66+
type: "object",
67+
properties: { city: { type: "string" } },
68+
required: ["city"],
69+
},
70+
},
71+
},
72+
],
73+
});
74+
console.log(result.chatOutput?.tool_calls);
75+
```
76+
77+
### Completion
78+
79+
```typescript
80+
const result = await client.llm.completion({
81+
model: TEE_LLM.CLAUDE_3_5_HAIKU,
82+
prompt: "The capital of France is",
83+
maxTokens: 20,
84+
});
85+
console.log(result.completionOutput);
86+
```
87+
88+
## x402 Settlement Modes
89+
90+
```typescript
91+
import { X402SettlementMode } from "opengradient-sdk";
92+
93+
await client.llm.chat({
94+
model: TEE_LLM.GPT_4O,
95+
messages: [{ role: "user", content: "Hi" }],
96+
x402SettlementMode: X402SettlementMode.SETTLE_BATCH, // default
1997
});
98+
```
99+
100+
- `SETTLE` — records input/output hashes only (most privacy-preserving).
101+
- `SETTLE_METADATA` — records full model info, complete input/output, and metadata.
102+
- `SETTLE_BATCH` — aggregates multiple inferences into a single on-chain settlement (most cost-efficient, default).
20103

21-
// Run LLM chat inference
22-
const [txHash, finishReason, response] = await client.llmChat(
23-
'Qwen/Qwen2.5-72B-Instruct',
24-
LLMInferenceMode.VANILLA,
25-
[{ role: 'user', content: 'Hello!' }],
26-
100 // max tokens
27-
);
28-
29-
// Run general model inference
30-
const modelInput = {
31-
num_input1: [1.0, 2.0, 3.0],
32-
num_input2: 10,
33-
str_input1: ["hello", "ONNXY"],
34-
str_input2: " world"
35-
};
36-
37-
const [txHash, output] = await client.infer(
38-
"QmbUqS93oc4JTLMHwpVxsE39mhNxy6hpf6Py3r9oANr8aZ",
39-
InferenceMode.VANILLA,
40-
modelInput
41-
);
104+
## Development
105+
106+
```bash
107+
npm install # install deps
108+
npm run lint # ESLint over src/
109+
npm test # Jest unit tests
110+
npm run build # tsc → dist/
111+
npm run format # prettier --write
42112
```
43113

44-
## Features
114+
CI runs `lint`, `test`, and `build` on Node 18 and 20 — see `.github/workflows/ci.yml`.
45115

46-
- On-chain ML model inference
47-
- LLM completion and chat interfaces
48-
- Support for vanilla, ZKML and TEE (Trusted Execution Environment) inference modes
49-
- Automatic transaction retry with configurable parameters
50-
- Built-in gas estimation and management
51-
- Tool calling support for LLM chat
116+
## Available models
52117

53-
## Contributing
118+
See `TEE_LLM` for the supported models, including:
54119

55-
We welcome contributions! Please check our contribution guidelines for more details.
120+
- `TEE_LLM.GPT_4O`, `TEE_LLM.GPT_4_1_2025_04_14`, `TEE_LLM.O4_MINI`
121+
- `TEE_LLM.CLAUDE_3_5_HAIKU`, `TEE_LLM.CLAUDE_3_7_SONNET`, `TEE_LLM.CLAUDE_4_0_SONNET`
122+
- `TEE_LLM.GEMINI_2_0_FLASH`, `TEE_LLM.GEMINI_2_5_FLASH`, `TEE_LLM.GEMINI_2_5_FLASH_LITE`, `TEE_LLM.GEMINI_2_5_PRO`
123+
- `TEE_LLM.GROK_2_1212`, `TEE_LLM.GROK_2_VISION_LATEST`, `TEE_LLM.GROK_3_BETA`, `TEE_LLM.GROK_3_MINI_BETA`, `TEE_LLM.GROK_4_1_FAST`, `TEE_LLM.GROK_4_1_FAST_NON_REASONING`

eslint.config.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const tseslint = require("@typescript-eslint/eslint-plugin");
2+
const tsparser = require("@typescript-eslint/parser");
3+
4+
module.exports = [
5+
{
6+
ignores: ["dist/**", "node_modules/**", "examples/**"],
7+
},
8+
{
9+
files: ["src/**/*.ts"],
10+
languageOptions: {
11+
parser: tsparser,
12+
parserOptions: {
13+
ecmaVersion: 2020,
14+
sourceType: "module",
15+
},
16+
},
17+
plugins: {
18+
"@typescript-eslint": tseslint,
19+
},
20+
rules: {
21+
...tseslint.configs.recommended.rules,
22+
"@typescript-eslint/no-unused-vars": [
23+
"error",
24+
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
25+
],
26+
"@typescript-eslint/no-explicit-any": "off",
27+
},
28+
},
29+
];

examples/llm_chat.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Run a non-streaming chat completion against a TEE-hosted LLM through
2+
// OpenGradient with x402 payments.
3+
//
4+
// Run with: OG_PRIVATE_KEY=0x... npx ts-node examples/llm_chat.ts
5+
6+
import { Client, TEE_LLM, X402SettlementMode } from "../src";
7+
8+
async function main() {
9+
const privateKey = process.env.OG_PRIVATE_KEY;
10+
if (!privateKey) {
11+
throw new Error("OG_PRIVATE_KEY environment variable is not set");
12+
}
13+
14+
const client = new Client({ privateKey });
15+
16+
const messages = [
17+
{ role: "user", content: "What is Python?" },
18+
{ role: "assistant", content: "Python is a high-level programming language." },
19+
{ role: "user", content: "What makes it good for beginners?" },
20+
];
21+
22+
const result = await client.llm.chat({
23+
model: TEE_LLM.GPT_4_1_2025_04_14,
24+
messages,
25+
x402SettlementMode: X402SettlementMode.SETTLE_METADATA,
26+
});
27+
28+
console.log(`Response: ${result.chatOutput?.content}`);
29+
console.log(`Payment hash: ${result.paymentHash}`);
30+
}
31+
32+
main().catch((err) => {
33+
console.error(err);
34+
process.exit(1);
35+
});

examples/llm_chat_stream.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Stream a chat completion from a TEE-hosted LLM through OpenGradient
2+
// with x402 payments.
3+
//
4+
// Run with: OG_PRIVATE_KEY=0x... npx ts-node examples/llm_chat_stream.ts
5+
6+
import { Client, TEE_LLM, X402SettlementMode } from "../src";
7+
8+
async function main() {
9+
const privateKey = process.env.OG_PRIVATE_KEY;
10+
if (!privateKey) {
11+
throw new Error("OG_PRIVATE_KEY environment variable is not set");
12+
}
13+
14+
const client = new Client({ privateKey });
15+
16+
const messages = [
17+
{ role: "user", content: "Describe to me the 7 network layers?" },
18+
];
19+
20+
const stream = client.llm.chat({
21+
model: TEE_LLM.GPT_4_1_2025_04_14,
22+
messages,
23+
x402SettlementMode: X402SettlementMode.SETTLE_METADATA,
24+
stream: true,
25+
maxTokens: 1000,
26+
});
27+
28+
for await (const chunk of stream) {
29+
const content = chunk.choices[0]?.delta.content;
30+
if (content) process.stdout.write(content);
31+
}
32+
process.stdout.write("\n");
33+
}
34+
35+
main().catch((err) => {
36+
console.error(err);
37+
process.exit(1);
38+
});

0 commit comments

Comments
 (0)