Skip to content

Commit b655ee6

Browse files
authored
System prompt v2 (#12)
* System prompt v2 * Fmt * fix: add prettier config and format all files for CI consistency * Fmt * Agent sdk * Lock * prettier ignore
1 parent 3df62ac commit b655ee6

23 files changed

Lines changed: 7516 additions & 8823 deletions

.github/workflows/pull-request.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ jobs:
2727
- name: Setup Node
2828
uses: actions/setup-node@v5
2929
with:
30-
node-version: "22"
31-
cache: "pnpm"
30+
node-version: '22'
31+
cache: 'pnpm'
3232

3333
- name: Install Dependencies
3434
run: pnpm install --frozen-lockfile

.prettierignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pnpm-lock.yaml
2+
node_modules
3+
.next
4+
dist
5+
build
6+

.prettierrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"semi": false,
3+
"singleQuote": true,
4+
"tabWidth": 2,
5+
"trailingComma": "es5",
6+
"printWidth": 100,
7+
"endOfLine": "lf"
8+
}

README.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ The system comes with a proven Wall Street 3-step strategy:
1616
// From lib/strategies/index.ts
1717
export const DEFAULT_STRATEGY: StrategyConfig = {
1818
overview:
19-
"Wall Street 3-Step: Data-driven day trading with clear profit/loss targets and risk management",
19+
'Wall Street 3-Step: Data-driven day trading with clear profit/loss targets and risk management',
2020
riskParams: {
2121
profitTarget: 2, // +2% profit target
2222
stopLoss: -1.5, // -1.5% stop loss
2323
maxPositions: 4, // Max 4 open positions
24-
positionSize: "5-15% of USDC",
24+
positionSize: '5-15% of USDC',
2525
},
2626
step1Rules:
27-
"Risk targets: SELL at +2% profit OR -1.5% loss. Close losing positions faster than winners (cut losses, let profits run). .",
27+
'Risk targets: SELL at +2% profit OR -1.5% loss. Close losing positions faster than winners (cut losses, let profits run). .',
2828
step2Rules:
29-
"Screen for high-probability setups: Price momentum >3% with volume confirmation, Fear/Greed extremes, Order book imbalances. Use 1 analysis tool only if market data insufficient. Only trade clear directional moves.",
29+
'Screen for high-probability setups: Price momentum >3% with volume confirmation, Fear/Greed extremes, Order book imbalances. Use 1 analysis tool only if market data insufficient. Only trade clear directional moves.',
3030
step3Rules:
31-
"Dynamic sizing: 5-15% per trade (scales with account). Size calculation: Min($10, Max($5, USDC_balance * 0.10)). Account for slippage: Minimum $8 positions. Max 3-4 open positions at once.",
32-
};
31+
'Dynamic sizing: 5-15% per trade (scales with account). Size calculation: Min($10, Max($5, USDC_balance * 0.10)). Account for slippage: Minimum $8 positions. Max 3-4 open positions at once.',
32+
}
3333
```
3434

3535
### Available Tools
@@ -46,17 +46,17 @@ All strategies have access to these trading tools:
4646

4747
```typescript
4848
const template: StrategyConfig = {
49-
overview: "Your Strategy Name: What does your strategy do?",
49+
overview: 'Your Strategy Name: What does your strategy do?',
5050
riskParams: {
5151
profitTarget: 2, // % profit to exit
5252
stopLoss: -1.5, // % loss to exit
5353
maxPositions: 4, // Max open positions
54-
positionSize: "5-15% of USDC", // Position sizing
54+
positionSize: '5-15% of USDC', // Position sizing
5555
},
56-
step1Rules: "When and how to close existing positions...",
57-
step2Rules: "What market conditions to look for...",
58-
step3Rules: "How to size and execute new positions...",
59-
};
56+
step1Rules: 'When and how to close existing positions...',
57+
step2Rules: 'What market conditions to look for...',
58+
step3Rules: 'How to size and execute new positions...',
59+
}
6060
```
6161

6262
### Core Infrastructure

app/api/deposit/route.ts

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,49 @@
1-
import { NextRequest, NextResponse } from "next/server";
2-
import { BALANCE_UPDATE_DELAY } from "@/lib/utils";
3-
import { initializeNearAccount, depositUSDC, getUSDCBalance } from "@/lib/near";
4-
import { formatUnits } from "@/lib/viem";
5-
import { withCronSecret } from "@/lib/api-auth";
6-
import { getEnvVar } from "@/lib/env";
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { BALANCE_UPDATE_DELAY } from '@/lib/utils'
3+
import { initializeNearAccount, depositUSDC, getUSDCBalance } from '@/lib/near'
4+
import { formatUnits } from '@/lib/viem'
5+
import { withCronSecret } from '@/lib/api-auth'
6+
import { getEnvVar } from '@/lib/env'
77

88
async function depositHandler(request: NextRequest) {
99
try {
10-
const accountId = getEnvVar("NEXT_PUBLIC_ACCOUNT_ID");
11-
const { searchParams } = new URL(request.url);
12-
const depositStr = searchParams.get("amount");
10+
const accountId = getEnvVar('NEXT_PUBLIC_ACCOUNT_ID')
11+
const { searchParams } = new URL(request.url)
12+
const depositStr = searchParams.get('amount')
1313
if (!depositStr) {
14-
return NextResponse.json(
15-
{ error: "unspecified amount" },
16-
{ status: 400 },
17-
);
14+
return NextResponse.json({ error: 'unspecified amount' }, { status: 400 })
1815
}
1916

20-
const depositAmount = BigInt(depositStr);
17+
const depositAmount = BigInt(depositStr)
2118

22-
const account = await initializeNearAccount(accountId);
19+
const account = await initializeNearAccount(accountId)
2320

24-
const usdcBalance = await getUSDCBalance(account);
21+
const usdcBalance = await getUSDCBalance(account)
2522

2623
if (usdcBalance < depositAmount) {
2724
return NextResponse.json(
2825
{
2926
error: `Insufficient USDC balance (required: $${depositAmount}, available: $${usdcBalance})`,
3027
},
31-
{ status: 400 },
32-
);
28+
{ status: 400 }
29+
)
3330
}
3431

35-
const tx = await depositUSDC(account, depositAmount);
32+
const tx = await depositUSDC(account, depositAmount)
3633

37-
await new Promise((resolve) => setTimeout(resolve, BALANCE_UPDATE_DELAY));
34+
await new Promise((resolve) => setTimeout(resolve, BALANCE_UPDATE_DELAY))
3835

39-
const uiAmount = formatUnits(depositAmount, 6);
36+
const uiAmount = formatUnits(depositAmount, 6)
4037

4138
return NextResponse.json({
4239
message: `Successfully deposited $${uiAmount} USDC`,
4340
transactionHash: tx.transaction.hash,
4441
amount: uiAmount,
45-
});
42+
})
4643
} catch (error) {
47-
console.error("Error in deposit endpoint:", error);
48-
return NextResponse.json(
49-
{ error: "Failed to process deposit request" },
50-
{ status: 500 },
51-
);
44+
console.error('Error in deposit endpoint:', error)
45+
return NextResponse.json({ error: 'Failed to process deposit request' }, { status: 500 })
5246
}
5347
}
5448

55-
export const GET = withCronSecret(depositHandler);
49+
export const GET = withCronSecret(depositHandler)

app/api/trade/route.ts

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,70 @@
1-
import { NextResponse } from "next/server";
2-
import { BALANCE_UPDATE_DELAY, logTradingAgentData } from "@/lib/utils";
3-
import { storeTrade, storePortfolioSnapshot } from "@/lib/api-helpers";
4-
import { buildTransactionPayload, initializeNearAccount } from "@/lib/near";
5-
import { buildAgentContext } from "@/lib/agent-context";
6-
import { callAgent } from "@bitte-ai/agent-sdk";
7-
import { ToolResult } from "@/lib/types";
8-
import { withCronSecret } from "@/lib/api-auth";
9-
import { getEnvVar } from "@/lib/env";
1+
import { NextResponse } from 'next/server'
2+
import { BALANCE_UPDATE_DELAY, logTradingAgentData } from '@/lib/utils'
3+
import { storeTrade, storePortfolioSnapshot } from '@/lib/api-helpers'
4+
import { buildTransactionPayload, initializeNearAccount } from '@/lib/near'
5+
import { AGENT_TRIGGER_MESSAGE, buildAgentContext } from '@/lib/agent-context'
6+
import { callAgent } from '@bitte-ai/agent-sdk'
7+
import { ToolResult } from '@/lib/types'
8+
import { withCronSecret } from '@/lib/api-auth'
9+
import { getEnvVar } from '@/lib/env'
1010

1111
async function tradeHandler(): Promise<NextResponse> {
1212
try {
13-
const accountId = getEnvVar("NEXT_PUBLIC_ACCOUNT_ID");
14-
const agentId = "trading-agent-kappa.vercel.app";
13+
const accountId = getEnvVar('NEXT_PUBLIC_ACCOUNT_ID')
14+
const agentId = 'trading-agent-kappa.vercel.app'
1515

16-
const account = await initializeNearAccount(accountId);
16+
const account = await initializeNearAccount(accountId)
1717

18-
const context = await buildAgentContext(accountId, account);
18+
const context = await buildAgentContext(accountId, account)
1919

20-
const { content, toolResults } = await callAgent(
20+
const { content, toolResults } = await callAgent({
2121
accountId,
22-
context.systemPrompt,
22+
message: AGENT_TRIGGER_MESSAGE,
2323
agentId,
24-
);
24+
systemPrompt: context.systemPrompt,
25+
})
2526

2627
const quoteResult = (toolResults as ToolResult[]).find(
27-
(callResult) => callResult.result?.data?.data?.quote,
28-
);
29-
const quote = quoteResult?.result?.data?.data?.quote;
28+
(callResult) => callResult.result?.data?.data?.quote
29+
)
30+
const quote = quoteResult?.result?.data?.data?.quote
3031

3132
logTradingAgentData({
3233
context,
3334
content,
3435
pnlUsd: context.totalPnl,
3536
quoteResult,
36-
});
37+
})
3738

3839
if (quote) {
39-
const tx = await account.signAndSendTransaction(
40-
buildTransactionPayload(quote),
41-
);
42-
console.log("Trade executed:", tx.transaction.hash);
43-
await new Promise((resolve) => setTimeout(resolve, BALANCE_UPDATE_DELAY));
44-
await storeTrade(accountId, quote);
40+
const tx = await account.signAndSendTransaction(buildTransactionPayload(quote))
41+
console.log('Trade executed:', tx.transaction.hash)
42+
await new Promise((resolve) => setTimeout(resolve, BALANCE_UPDATE_DELAY))
43+
await storeTrade(accountId, quote)
4544

46-
const updatedContext = await buildAgentContext(accountId, account);
45+
const updatedContext = await buildAgentContext(accountId, account)
4746

4847
await storePortfolioSnapshot(
4948
accountId,
5049
updatedContext.positionsWithPnl,
5150
updatedContext.totalUsd,
5251
context.totalUsd,
53-
content,
54-
);
52+
content
53+
)
5554
} else {
5655
await storePortfolioSnapshot(
5756
accountId,
5857
context.positionsWithPnl,
5958
context.totalUsd,
6059
context.totalUsd,
61-
content,
62-
);
60+
content
61+
)
6362
}
64-
return NextResponse.json({ content });
63+
return NextResponse.json({ content })
6564
} catch (error) {
66-
console.error("Error in trading endpoint:", error);
67-
return NextResponse.json(
68-
{ error: "Failed to process trading request" },
69-
{ status: 500 },
70-
);
65+
console.error('Error in trading endpoint:', error)
66+
return NextResponse.json({ error: 'Failed to process trading request' }, { status: 500 })
7167
}
7268
}
7369

74-
export const GET = withCronSecret(tradeHandler);
70+
export const GET = withCronSecret(tradeHandler)

app/api/withdraw/route.ts

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,56 @@
1-
import { NextRequest, NextResponse } from "next/server";
2-
import { BALANCE_UPDATE_DELAY, USDC_CONTRACT } from "@/lib/utils";
3-
import {
4-
initializeNearAccount,
5-
withdrawToken,
6-
intentsBalance,
7-
} from "@/lib/near";
8-
import { formatUnits } from "@/lib/viem";
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { BALANCE_UPDATE_DELAY, USDC_CONTRACT } from '@/lib/utils'
3+
import { initializeNearAccount, withdrawToken, intentsBalance } from '@/lib/near'
4+
import { formatUnits } from '@/lib/viem'
95

10-
const bigIntMin = (a: bigint, b: bigint) => (a < b ? a : b);
11-
const ZERO = BigInt(0);
6+
const bigIntMin = (a: bigint, b: bigint) => (a < b ? a : b)
7+
const ZERO = BigInt(0)
128

139
export async function GET(request: NextRequest) {
1410
try {
1511
if (process.env.CRON_SECRET) {
16-
const authHeader = request.headers.get("Authorization");
12+
const authHeader = request.headers.get('Authorization')
1713
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
18-
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
14+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
1915
}
2016
}
2117

22-
const { searchParams } = new URL(request.url);
23-
const withdrawStr = searchParams.get("amount");
18+
const { searchParams } = new URL(request.url)
19+
const withdrawStr = searchParams.get('amount')
2420
if (!withdrawStr) {
25-
return NextResponse.json(
26-
{ error: "unspecified amount" },
27-
{ status: 400 },
28-
);
21+
return NextResponse.json({ error: 'unspecified amount' }, { status: 400 })
2922
}
30-
const token = searchParams.get("token") || USDC_CONTRACT;
23+
const token = searchParams.get('token') || USDC_CONTRACT
3124

32-
const accountId = process.env.NEXT_PUBLIC_ACCOUNT_ID;
25+
const accountId = process.env.NEXT_PUBLIC_ACCOUNT_ID
3326
if (!accountId) {
34-
return NextResponse.json(
35-
{ error: "accountId is not configured" },
36-
{ status: 500 },
37-
);
27+
return NextResponse.json({ error: 'accountId is not configured' }, { status: 500 })
3828
}
3929

40-
const requestedWithdrawAmount = BigInt(withdrawStr);
30+
const requestedWithdrawAmount = BigInt(withdrawStr)
4131

42-
const account = await initializeNearAccount(accountId);
32+
const account = await initializeNearAccount(accountId)
4333

44-
const usdcBalance = await intentsBalance(account, token);
45-
const withdrawAmount = bigIntMin(requestedWithdrawAmount, usdcBalance);
34+
const usdcBalance = await intentsBalance(account, token)
35+
const withdrawAmount = bigIntMin(requestedWithdrawAmount, usdcBalance)
4636

4737
if (withdrawAmount == ZERO) {
48-
return NextResponse.json(
49-
{ message: "Nothing to withdraw" },
50-
{ status: 200 },
51-
);
38+
return NextResponse.json({ message: 'Nothing to withdraw' }, { status: 200 })
5239
}
5340

54-
const tx = await withdrawToken(account, token, withdrawAmount);
41+
const tx = await withdrawToken(account, token, withdrawAmount)
5542

56-
await new Promise((resolve) => setTimeout(resolve, BALANCE_UPDATE_DELAY));
43+
await new Promise((resolve) => setTimeout(resolve, BALANCE_UPDATE_DELAY))
5744

58-
const uiAmount = formatUnits(withdrawAmount, 6);
45+
const uiAmount = formatUnits(withdrawAmount, 6)
5946

6047
return NextResponse.json({
6148
message: `Successfully withdrew $${uiAmount} USDC`,
6249
transactionHash: tx.transaction.hash,
6350
amount: uiAmount,
64-
});
51+
})
6552
} catch (error) {
66-
console.error("Error in deposit endpoint:", error);
67-
return NextResponse.json(
68-
{ error: "Failed to process deposit request" },
69-
{ status: 500 },
70-
);
53+
console.error('Error in deposit endpoint:', error)
54+
return NextResponse.json({ error: 'Failed to process deposit request' }, { status: 500 })
7155
}
7256
}

app/layout.tsx

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export const metadata = {
2-
title: "Autonomous Trading Agent",
3-
description: "Deployment status page",
4-
};
2+
title: 'Autonomous Trading Agent',
3+
description: 'Deployment status page',
4+
}
55

66
const styles = `
77
* { margin: 0; padding: 0; box-sizing: border-box; }
@@ -18,13 +18,9 @@ const styles = `
1818
.description { font-size: 18px; }
1919
.button { width: 100%; max-width: 280px; }
2020
}
21-
`;
21+
`
2222

23-
export default function RootLayout({
24-
children,
25-
}: {
26-
children: React.ReactNode;
27-
}) {
23+
export default function RootLayout({ children }: { children: React.ReactNode }) {
2824
return (
2925
<html lang="en">
3026
<head>
@@ -38,5 +34,5 @@ export default function RootLayout({
3834
{children}
3935
</body>
4036
</html>
41-
);
37+
)
4238
}

0 commit comments

Comments
 (0)