Skip to content

Commit 0b62397

Browse files
[SDK] feat: Support multiple messages in Nebula API and update input props (#5972)
1 parent df4da68 commit 0b62397

File tree

6 files changed

+178
-26
lines changed

6 files changed

+178
-26
lines changed

.changeset/rude-sheep-hear.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
---
2+
"thirdweb": minor
3+
---
4+
5+
Support multiple messages for Nebula API, updated input props.
6+
7+
Some prop names have been updated:
8+
9+
`prompt -> messsage`
10+
`context -> contextFilter`
11+
12+
```ts
13+
Nebula.chat({
14+
client,
15+
// prompt is now message
16+
message:
17+
"What's the total supply of this contract: 0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
18+
// contextFilter is now contextFilter
19+
contextFilter: {
20+
chains: [sepolia],
21+
},
22+
});
23+
```
24+
25+
The Nebula.chat and Nebula.execute functions now support multiple input messages, and the input properties have been updated to match the http API.
26+
27+
```ts
28+
Nebula.chat({
29+
client,
30+
// multi message format
31+
messages: [
32+
{
33+
role: "user",
34+
content:
35+
"Tell me the name of this contract: 0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
36+
},
37+
{
38+
role: "assistant",
39+
content: "The name of the contract is My NFT Collection",
40+
},
41+
{
42+
role: "user",
43+
content: "What's the symbol of this contract?",
44+
},
45+
],
46+
contextFilter: {
47+
chains: [sepolia],
48+
},
49+
});
50+
```
51+
52+
Same changes apply to Nebula.execute.
53+
54+
```ts
55+
Nebula.execute({
56+
client,
57+
account,
58+
messages: [
59+
{ role: "user", content: "What's the address of vitalik.eth" },
60+
{
61+
role: "assistant",
62+
content:
63+
"The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298",
64+
},
65+
{ role: "user", content: "Send them 0.0001 ETH" },
66+
],
67+
contextFilter: {
68+
chains: [sepolia],
69+
},
70+
});
71+
```

packages/thirdweb/src/ai/chat.test.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ describe.runIf(process.env.TW_SECRET_KEY).skip("chat", () => {
99
it("should respond with a message", async () => {
1010
const response = await Nebula.chat({
1111
client: TEST_CLIENT,
12-
prompt: `What's the symbol of this contract: 0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8`,
13-
context: {
12+
messages: [
13+
{
14+
role: "user",
15+
content: `What's the symbol of this contract: 0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8`,
16+
},
17+
],
18+
contextFilter: {
1419
chains: [sepolia],
1520
},
1621
});
@@ -20,9 +25,14 @@ describe.runIf(process.env.TW_SECRET_KEY).skip("chat", () => {
2025
it("should respond with a transaction", async () => {
2126
const response = await Nebula.chat({
2227
client: TEST_CLIENT,
23-
prompt: `send 0.0001 ETH on sepolia to ${TEST_ACCOUNT_B.address}`,
28+
messages: [
29+
{
30+
role: "user",
31+
content: `send 0.0001 ETH on sepolia to ${TEST_ACCOUNT_B.address}`,
32+
},
33+
],
2434
account: TEST_ACCOUNT_A,
25-
context: {
35+
contextFilter: {
2636
chains: [sepolia],
2737
walletAddresses: [TEST_ACCOUNT_A.address],
2838
},

packages/thirdweb/src/ai/chat.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { type Input, type Output, nebulaFetch } from "./common.js";
55
*
66
* @param input - The input for the chat.
77
* @returns The chat response.
8-
* @beta
8+
* @beta This API is in early access and might change in the future.
99
* @nebula
1010
*
1111
* @example
@@ -14,12 +14,38 @@ import { type Input, type Output, nebulaFetch } from "./common.js";
1414
*
1515
* const response = await Nebula.chat({
1616
* client: TEST_CLIENT,
17-
* prompt: "What's the symbol of this contract: 0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
18-
* context: {
17+
* message: "What's the symbol of this contract: 0xe2cb0eb5147b42095c2FfA6F7ec953bb0bE347D8",
18+
* contextFilter: {
1919
* chains: [sepolia],
2020
* },
2121
* });
2222
* ```
23+
*
24+
* Multi message prompt:
25+
*
26+
* ```ts
27+
* const response = await Nebula.chat({
28+
* client,
29+
* messages: [
30+
* { role: "user", content: "What's my balance?" },
31+
* { role: "assistant", content: "Your balance is 0.023 ETH" },
32+
* { role: "user", content: "What about my NFTs?" },
33+
* ],
34+
* contextFilter: {
35+
* chains: [sepolia],
36+
* },
37+
* });
38+
* ```
39+
*
40+
* Extracting and sending transactions from a chat response:
41+
*
42+
* ```ts
43+
* const response = await Nebula.chat({ ... });
44+
* const transactions = response.transactions;
45+
* for (const transaction of transactions) {
46+
* await sendTransaction({ transaction, account });
47+
* }
48+
* ```
2349
*/
2450
export async function chat(input: Input): Promise<Output> {
2551
return nebulaFetch("chat", input);

packages/thirdweb/src/ai/common.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,24 @@ const NEBULA_API_URL = "https://nebula-api.thirdweb.com";
1515

1616
export type Input = {
1717
client: ThirdwebClient;
18-
prompt: string | string[];
1918
account?: Account;
20-
context?: {
19+
contextFilter?: {
2120
chains?: Chain[];
2221
walletAddresses?: string[];
2322
contractAddresses?: string[];
2423
};
2524
sessionId?: string;
26-
};
25+
} & (
26+
| {
27+
messages: {
28+
role: "user" | "assistant";
29+
content: string;
30+
}[];
31+
}
32+
| {
33+
message: string;
34+
}
35+
);
2736

2837
export type Output = {
2938
message: string;
@@ -52,7 +61,13 @@ export async function nebulaFetch(
5261
"Content-Type": "application/json",
5362
},
5463
body: JSON.stringify({
55-
message: input.prompt, // TODO: support array of messages
64+
...("messages" in input
65+
? {
66+
messages: input.messages,
67+
}
68+
: {
69+
message: input.message,
70+
}),
5671
session_id: input.sessionId,
5772
...(input.account
5873
? {
@@ -62,13 +77,15 @@ export async function nebulaFetch(
6277
},
6378
}
6479
: {}),
65-
...(input.context
80+
...(input.contextFilter
6681
? {
6782
context_filter: {
6883
chain_ids:
69-
input.context.chains?.map((c) => c.id.toString()) || [],
70-
signer_wallet_address: input.context.walletAddresses || [],
71-
contract_addresses: input.context.contractAddresses || [],
84+
input.contextFilter.chains?.map((c) => c.id.toString()) || [],
85+
wallet_addresses:
86+
input.contextFilter.walletAddresses ||
87+
(input.account ? [input.account.address] : []),
88+
contract_addresses: input.contextFilter.contractAddresses || [],
7289
},
7390
}
7491
: {}),

packages/thirdweb/src/ai/execute.test.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ describe.runIf(process.env.TW_SECRET_KEY).skip("execute", () => {
1111
await expect(
1212
Nebula.execute({
1313
client: TEST_CLIENT,
14-
prompt: `send 0.0001 ETH to ${TEST_ACCOUNT_B.address}`,
14+
message: `send 0.0001 ETH to ${TEST_ACCOUNT_B.address}`,
1515
account: TEST_ACCOUNT_A,
16-
context: {
16+
contextFilter: {
1717
chains: [sepolia],
1818
walletAddresses: [TEST_ACCOUNT_A.address],
1919
},
@@ -22,7 +22,7 @@ describe.runIf(process.env.TW_SECRET_KEY).skip("execute", () => {
2222
});
2323

2424
// TODO make this work reliably
25-
it.skip("should execute a contract call", async () => {
25+
it("should execute a contract call", async () => {
2626
const nftContract = getContract({
2727
client: TEST_CLIENT,
2828
chain: sepolia,
@@ -31,11 +31,15 @@ describe.runIf(process.env.TW_SECRET_KEY).skip("execute", () => {
3131

3232
const response = await Nebula.execute({
3333
client: TEST_CLIENT,
34-
prompt: `approve 1 token of token id 0 to ${TEST_ACCOUNT_B.address} using the approve function`,
34+
messages: [
35+
{
36+
role: "user",
37+
content: `approve 1 token of token id 0 to ${TEST_ACCOUNT_B.address} using the approve function`,
38+
},
39+
],
3540
account: TEST_ACCOUNT_A,
36-
context: {
41+
contextFilter: {
3742
chains: [nftContract.chain],
38-
walletAddresses: [TEST_ACCOUNT_A.address],
3943
contractAddresses: [nftContract.address],
4044
},
4145
});

packages/thirdweb/src/ai/execute.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,46 @@ import { type Input, nebulaFetch } from "./common.js";
88
*
99
* @param input - The input for the transaction.
1010
* @returns The transaction hash.
11-
* @beta
11+
* @beta This API is in early access and might change in the future.
1212
* @nebula
1313
*
1414
* @example
1515
* ```ts
1616
* import { Nebula } from "thirdweb/ai";
1717
*
18+
* const wallet = createWallet("io.metamask");
19+
* const account = wallet.connect({ client });
20+
*
1821
* const result = await Nebula.execute({
19-
* client: TEST_CLIENT,
20-
* prompt: "send 0.0001 ETH to vitalik.eth",
21-
* account: TEST_ACCOUNT_A,
22-
* context: {
22+
* client,
23+
* account, // transactions will be sent from this account
24+
* message: "send 0.0001 ETH to vitalik.eth",
25+
* contextFilter: {
2326
* chains: [sepolia],
2427
* },
2528
* });
2629
* ```
30+
*
31+
* Multi message prompt:
32+
*
33+
* ```ts
34+
* Nebula.execute({
35+
* client,
36+
* account,
37+
* messages: [
38+
* { role: "user", content: "What's the address of vitalik.eth" },
39+
* {
40+
* role: "assistant",
41+
* content:
42+
* "The address of vitalik.eth is 0xd8dA6BF26964aF8E437eEa5e3616511D7G3a3298",
43+
* },
44+
* { role: "user", content: "Send them 0.0001 ETH" },
45+
* ],
46+
* contextFilter: {
47+
* chains: [sepolia],
48+
* },
49+
* });
50+
* ```
2751
*/
2852
export async function execute(
2953
input: Input & { account: Account },

0 commit comments

Comments
 (0)