Skip to content

[TOOL-2894] Portal: Nebula API docs #5877

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/dashboard/src/app/nebula-app/(app)/api/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export async function promptNebula(params: {
body.context_filter = {
chain_ids: params.contextFilters.chainIds || [],
contract_addresses: params.contextFilters.contractAddresses || [],
wallet_addresses: params.contextFilters.walletAddresses || [],
};
}

Expand Down
173 changes: 87 additions & 86 deletions apps/portal/mdx-components.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CodeBlock, InlineCode } from "@/components/Document/Code";
import { CodeBlock } from "@/components/Document/Code";
import { DocLink } from "@/components/Document/DocLink";
import { Heading } from "@/components/Document/Heading";
import { OrderedList, UnorderedList } from "@/components/Document/List";
Expand All @@ -8,97 +8,98 @@ import { TBody, Table, Td, Th, Tr } from "@/components/Document/Table";
import GithubSlugger from "github-slugger";
import type { MDXComponents } from "mdx/types";
import type { BuiltinLanguage } from "shiki";
import { InlineCode } from "./src/components/Document";

export function useMDXComponents(components: MDXComponents): MDXComponents {
const slugger = new GithubSlugger();
const slugger = new GithubSlugger();

function nameToLink(name: React.ReactNode) {
if (typeof name !== "string") {
return undefined;
}
function nameToLink(name: React.ReactNode) {
if (typeof name !== "string") {
return undefined;
}

return slugger.slug(name);
}
return slugger.slug(name);
}

function getHeading(
depth: number,
props: {
children?: React.ReactNode;
id?: string;
},
) {
return (
<Heading level={depth} id={props.id || nameToLink(props.children) || ""}>
{props.children}
</Heading>
);
}
function getHeading(
depth: number,
props: {
children?: React.ReactNode;
id?: string;
},
) {
return (
<Heading level={depth} id={props.id || nameToLink(props.children) || ""}>
{props.children}
</Heading>
);
}

return {
...components,
a(props) {
const { href, children } = props;
return <DocLink href={href || ""}>{children}</DocLink>;
},
h1(props) {
return getHeading(1, props);
},
h2(props) {
return getHeading(2, props);
},
h3(props) {
return getHeading(3, props);
},
h4(props) {
return getHeading(4, props);
},
h5(props) {
return getHeading(5, props);
},
h6(props) {
return getHeading(6, props);
},
code(props) {
const code = props.children;
const lang = props.className?.replace("language-", "");
return {
...components,
a(props) {
const { href, children } = props;
return <DocLink href={href || ""}>{children}</DocLink>;
},
h1(props) {
return getHeading(1, props);
},
h2(props) {
return getHeading(2, props);
},
h3(props) {
return getHeading(3, props);
},
h4(props) {
return getHeading(4, props);
},
h5(props) {
return getHeading(5, props);
},
h6(props) {
return getHeading(6, props);
},
code(props) {
const code = props.children;
const lang = props.className?.replace("language-", "");

if (!props.className) {
return <InlineCode code={typeof code === "string" ? code : ""} />;
}
if (!props.className) {
return <InlineCode code={typeof code === "string" ? code : ""} />;
}

return (
<CodeBlock
lang={lang as BuiltinLanguage}
code={typeof code === "string" ? code : ""}
/>
);
},
p(props) {
return <Paragraph>{props.children}</Paragraph>;
},
ul(props) {
return <UnorderedList>{props.children}</UnorderedList>;
},
ol(props) {
return <OrderedList>{props.children}</OrderedList>;
},
hr() {
return <Separator />;
},
table(props) {
return <Table>{props.children}</Table>;
},
th(props) {
return <Th>{props.children}</Th>;
},
td(props) {
return <Td>{props.children}</Td>;
},
tr(props) {
return <Tr>{props.children}</Tr>;
},
tbody(props) {
return <TBody>{props.children}</TBody>;
},
};
return (
<CodeBlock
lang={lang as BuiltinLanguage}
code={typeof code === "string" ? code : ""}
/>
);
},
p(props) {
return <Paragraph>{props.children}</Paragraph>;
},
ul(props) {
return <UnorderedList>{props.children}</UnorderedList>;
},
ol(props) {
return <OrderedList>{props.children}</OrderedList>;
},
hr() {
return <Separator />;
},
table(props) {
return <Table>{props.children}</Table>;
},
th(props) {
return <Th>{props.children}</Th>;
},
td(props) {
return <Td>{props.children}</Td>;
},
tr(props) {
return <Tr>{props.children}</Tr>;
},
tbody(props) {
return <TBody>{props.children}</TBody>;
},
};
}
1 change: 1 addition & 0 deletions apps/portal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@next/mdx": "15.1.0",
"@radix-ui/react-dialog": "1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.3",
"@radix-ui/react-select": "^2.1.3",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-tabs": "^1.1.2",
"@tanstack/react-query": "5.62.16",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { ApiEndpoint } from "@/components/Document/APIEndpointMeta/ApiEndpoint";
import {
nebulaAPI401Response,
nebulaAPI422Response,
nebulaContextFilterPathParameter,
nebulaExecuteConfigPathParameter,
nebulaSecretKeyHeaderParameter,
nebulaSessionIdPathParameter,
} from "../common";

const response200Example = `\
{
"message": "string",
"actions": [
{
"session_id": "string",
"request_id": "string",
"type": "init",
"source": "string",
"data": "string"
}
],
"session_id": "string",
"request_id": "string"
}`;

export function EndpointMetadata() {
return (
<ApiEndpoint
metadata={{
title: "Send Message",
description: "Process a chat message and return the response",
origin: "https://nebula-api.thirdweb.com",
path: "/chat",
method: "POST",
request: {
pathParameters: [],
headers: [nebulaSecretKeyHeaderParameter],
bodyParameters: [
{
name: "message",
required: true,
description: "The message to be processed.",
type: "string",
example: "Hello",
},
{
name: "stream",
required: false,
description: "Whether to stream the response or not",
type: "boolean",
example: false,
},
{
...nebulaSessionIdPathParameter,
required: false,
description:
"The session ID to associate with the message. If not provided, a new session will be created.",
},
nebulaExecuteConfigPathParameter,
nebulaContextFilterPathParameter,
],
},
responseExamples: {
200: response200Example,
401: nebulaAPI401Response,
422: nebulaAPI422Response,
},
}}
/>
);
}
89 changes: 8 additions & 81 deletions apps/portal/src/app/nebula/api-reference/chat/page.mdx
Original file line number Diff line number Diff line change
@@ -1,79 +1,6 @@
### Send Message
import { EndpointMetadata } from './EndpointMetadata';

```http
POST /chat
```

**Request Body:**
```json
{
"message": "Find the last 5 blocks",
"session_id": "abc",
"stream": true,
"context_filter": {
"chain_ids": [137],
"contract_addresses": ["0x..."],
"wallet_addresses": ["0x..."]
},
"execute_config": {
"mode": "client",
"signer_wallet_address": "0x..."
}
}
```

**Request Parameters:**

- `message` (required)
- Type: string
- Description: The user's input message or command to be processed by Nebula

- `session_id` (optional)
- Type: string
- Description: Identifier for maintaining conversation context
- Default: A new session will be created if omitted

- `stream` (optional)
- Type: boolean
- Description: Controls whether the response is streamed or returned as a single response
- Default: false

- `context_filter` (optional)
- Type: object
- Description: Controls which blockchain data sources are used for context
- Properties:
- `chain_ids`: Array of numbers representing blockchain network IDs
- `contract_addresses`: Array of strings containing contract addresses to focus on

- `execute_config` (optional)
- Type: object
- Description: Configuration for transaction execution
- Properties:
- `mode`: String indicating execution mode (currently only "client" is supported)
- `signer_wallet_address`: String containing the wallet address that will sign transactions

#### Chat Messages

Chat messages are natural language responses from Nebula. They appear in the `message` field of the response and provide formatted information, explanations, or answers to your queries. Messages can include formatted text, blockchain data, and technical details.

**Example Response with Chat Message:**
```json
{
"message": "The last block on the Arbitrum mainnet is block number **284204124**. Here are the details:\n\n- **Block Hash:** 0xf42e3d624ae1e3fd6b89d4680f39943eb1cd3b8f0606918ef818d3021b7724f1\n- **Parent Hash:** 0x4c45cd0964281833b070b633980d8f530debdd21dfbdbf6eddf96cc93cbaac8e\n- **Timestamp:** 1734063299\n- **Gas Used:** 5,064,851\n- **Gas Limit:** 1,125,899,906,842,624\n- **Base Fee per Gas:** 10,000,000\n- **Transaction Count:** 7\n- **Withdrawals Count:** 0\n\nIf you need any more information about this block or related transactions, feel free to ask!",
"actions": [],
"session_id": "5d579903-5a63-434f-8667-788adfae9304",
"request_id": "d46cfb80-de6a-48a6-9a97-746e1708d066"
}
```

Response properties:
- `message`: A formatted string containing the response, which may include:
- Markdown formatting for better readability
- Technical data (hashes, addresses, numbers)
- Structured information about blockchain state
- `actions`: Array of actions (empty when no transactions are needed)
- `session_id`: Unique identifier for the current session
- `request_id`: Unique identifier for the specific request
<EndpointMetadata />

#### Chat Actions

Expand Down Expand Up @@ -117,11 +44,11 @@ When handling actions:

**Example Implementation with thirdweb SDK:**
```javascript
import {
createThirdwebClient,
prepareTransaction,
import {
createThirdwebClient,
prepareTransaction,
sendTransaction,
privateKeyToAccount
privateKeyToAccount
} from "thirdweb";

// Example function to handle the API response
Expand All @@ -140,7 +67,7 @@ async function handleNebulaResponse(response) {
// Check if we have any actions
if (response.actions && response.actions.length > 0) {
const action = response.actions[0];

// Parse the transaction data from the action
const txData = JSON.parse(action.data);

Expand All @@ -159,7 +86,7 @@ async function handleNebulaResponse(response) {
transaction,
account
});

return result;
} catch (error) {
console.error("Error processing transaction:", error);
Expand Down
Loading
Loading