Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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/playground-web/src/app/ai/api/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export async function promptNebula(params: {
chain_ids: params.context.chainIds?.map(Number) || [],
session_id: params.context.sessionId ?? undefined,
wallet_address: params.context.walletAddress,
auto_execute_transactions: params.context.autoExecuteTransactions || false,
};
}

Expand Down
1 change: 1 addition & 0 deletions apps/playground-web/src/app/ai/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export type NebulaContext = {
chainIds: string[] | null;
walletAddress: string | null;
sessionId: string | null;
autoExecuteTransactions?: boolean;
};

export type NebulaSwapData = {
Expand Down
92 changes: 89 additions & 3 deletions apps/playground-web/src/app/ai/components/ChatPageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,19 @@ export function ChatPageContent(props: {
});

const contextFilters = useMemo(() => {
// Parse user-entered chain IDs
const userChainIdArray = userChainIds
.split(',')
.map(id => id.trim())
.filter(id => id !== '' && !isNaN(Number(id)));

return {
chainIds: _contextFilters?.chainIds || [],
chainIds: userChainIdArray.length > 0 ? userChainIdArray : (_contextFilters?.chainIds || []),
sessionId: _contextFilters?.sessionId || null,
walletAddress: address || _contextFilters?.walletAddress || null,
walletAddress: userWalletAddress.trim() || address || _contextFilters?.walletAddress || null,
autoExecuteTransactions: userAutoExecute,
} satisfies NebulaContext;
}, [_contextFilters, address]);
}, [_contextFilters, address, userWalletAddress, userChainIds, userAutoExecute]);

const setContextFilters = useCallback((v: NebulaContext | undefined) => {
_setContextFilters(v);
Expand Down Expand Up @@ -115,6 +122,11 @@ export function ChatPageContent(props: {
const [enableAutoScroll, setEnableAutoScroll] = useState(false);
const [showConnectModal, setShowConnectModal] = useState(false);

// User-configurable context options
const [userWalletAddress, setUserWalletAddress] = useState("");
const [userChainIds, setUserChainIds] = useState("");
const [userAutoExecute, setUserAutoExecute] = useState(false);

const handleSendMessage = useCallback(
async (message: NebulaUserMessage) => {
setUserHasSubmittedMessage(true);
Expand Down Expand Up @@ -227,6 +239,14 @@ export function ChatPageContent(props: {
{/* Chat input - anchored at bottom (same as chat state) */}
<div className="flex-shrink-0 border-t bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container max-w-[800px] py-4">
<ContextOptionsBar
walletAddress={userWalletAddress}
chainIds={userChainIds}
autoExecute={userAutoExecute}
onWalletAddressChange={setUserWalletAddress}
onChainIdsChange={setUserChainIds}
onAutoExecuteChange={setUserAutoExecute}
/>
<SimpleChatBar
abortChatStream={() => {
chatAbortController?.abort();
Expand Down Expand Up @@ -279,6 +299,14 @@ export function ChatPageContent(props: {
{/* Chat input - anchored at bottom */}
<div className="flex-shrink-0 border-t bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container max-w-[800px] py-4">
<ContextOptionsBar
walletAddress={userWalletAddress}
chainIds={userChainIds}
autoExecute={userAutoExecute}
onWalletAddressChange={setUserWalletAddress}
onChainIdsChange={setUserChainIds}
onAutoExecuteChange={setUserAutoExecute}
/>
<SimpleChatBar
abortChatStream={() => {
chatAbortController?.abort();
Expand Down Expand Up @@ -708,6 +736,64 @@ function RenderMessage(props: {
);
}

function ContextOptionsBar(props: {
walletAddress: string;
chainIds: string;
autoExecute: boolean;
onWalletAddressChange: (value: string) => void;
onChainIdsChange: (value: string) => void;
onAutoExecuteChange: (value: boolean) => void;
}) {
return (
<div className="mb-4 rounded-lg border bg-card p-3">
<div className="flex flex-wrap items-center gap-4">
<div className="flex items-center gap-2">
<label htmlFor="wallet-address" className="text-sm font-medium text-muted-foreground">
Wallet Address:
</label>
<input
id="wallet-address"
type="text"
value={props.walletAddress}
onChange={(e) => props.onWalletAddressChange(e.target.value)}
placeholder="0x..."
className="px-2 py-1 text-sm border border-border rounded focus:outline-none focus:ring-1 focus:ring-ring focus:border-ring bg-background"
style={{ width: "200px" }}
/>
</div>

<div className="flex items-center gap-2">
<label htmlFor="chain-ids" className="text-sm font-medium text-muted-foreground">
Chain IDs:
</label>
<input
id="chain-ids"
type="text"
value={props.chainIds}
onChange={(e) => props.onChainIdsChange(e.target.value)}
placeholder="1, 8453"
className="px-2 py-1 text-sm border border-border rounded focus:outline-none focus:ring-1 focus:ring-ring focus:border-ring bg-background"
style={{ width: "100px" }}
/>
</div>

<div className="flex items-center gap-2">
<input
id="auto-execute"
type="checkbox"
checked={props.autoExecute}
onChange={(e) => props.onAutoExecuteChange(e.target.checked)}
className="w-4 h-4 text-primary border-border rounded focus:ring-ring"
/>
<label htmlFor="auto-execute" className="text-sm font-medium text-muted-foreground">
Auto Execute Transactions
</label>
</div>
</div>
</div>
);
}

const NEBULA_LAST_USED_CHAIN_IDS_KEY = "nebula-last-used-chain-ids";

function saveLastUsedChainIds(chainIds: string[] | undefined) {
Expand Down
Loading
Loading