@mixrpay/agent-sdk 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -450
- package/dist/index.cjs +534 -0
- package/dist/index.d.cts +354 -1
- package/dist/index.d.ts +354 -1
- package/dist/index.js +534 -0
- package/package.json +2 -14
package/dist/index.cjs
CHANGED
|
@@ -1467,6 +1467,540 @@ var AgentWallet = class {
|
|
|
1467
1467
|
createdAt: new Date(data.createdAt || data.created_at)
|
|
1468
1468
|
};
|
|
1469
1469
|
}
|
|
1470
|
+
// ===========================================================================
|
|
1471
|
+
// MCP (Model Context Protocol) Methods
|
|
1472
|
+
// ===========================================================================
|
|
1473
|
+
/**
|
|
1474
|
+
* Get authentication headers for MCP wallet-based authentication.
|
|
1475
|
+
*
|
|
1476
|
+
* These headers prove wallet ownership without transmitting the private key.
|
|
1477
|
+
* Use for direct pay-per-call mode (no session needed).
|
|
1478
|
+
*
|
|
1479
|
+
* @returns Headers object with X-Mixr-Wallet, X-Mixr-Signature, X-Mixr-Timestamp
|
|
1480
|
+
*
|
|
1481
|
+
* @example
|
|
1482
|
+
* ```typescript
|
|
1483
|
+
* const headers = await wallet.getMCPAuthHeaders();
|
|
1484
|
+
* const response = await fetch('https://mixrpay.com/api/mcp', {
|
|
1485
|
+
* method: 'POST',
|
|
1486
|
+
* headers: {
|
|
1487
|
+
* 'Content-Type': 'application/json',
|
|
1488
|
+
* ...headers,
|
|
1489
|
+
* },
|
|
1490
|
+
* body: JSON.stringify({
|
|
1491
|
+
* jsonrpc: '2.0',
|
|
1492
|
+
* method: 'tools/list',
|
|
1493
|
+
* id: 1,
|
|
1494
|
+
* }),
|
|
1495
|
+
* });
|
|
1496
|
+
* ```
|
|
1497
|
+
*/
|
|
1498
|
+
async getMCPAuthHeaders() {
|
|
1499
|
+
const timestamp = Date.now().toString();
|
|
1500
|
+
const message = `MixrPay MCP Auth
|
|
1501
|
+
Wallet: ${this.walletAddress}
|
|
1502
|
+
Timestamp: ${timestamp}`;
|
|
1503
|
+
const signature = await this.sessionKey.signMessage(message);
|
|
1504
|
+
return {
|
|
1505
|
+
"X-Mixr-Wallet": this.walletAddress,
|
|
1506
|
+
"X-Mixr-Signature": signature,
|
|
1507
|
+
"X-Mixr-Timestamp": timestamp
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* List available MCP tools from the MixrPay gateway.
|
|
1512
|
+
*
|
|
1513
|
+
* Returns all tools exposed by MCP providers on the MixrPay marketplace.
|
|
1514
|
+
* Each tool includes pricing information.
|
|
1515
|
+
*
|
|
1516
|
+
* @returns Array of MCP tools with pricing and metadata
|
|
1517
|
+
*
|
|
1518
|
+
* @example
|
|
1519
|
+
* ```typescript
|
|
1520
|
+
* const tools = await wallet.listMCPTools();
|
|
1521
|
+
* for (const tool of tools) {
|
|
1522
|
+
* console.log(`${tool.name}: $${tool.priceUsd} - ${tool.description}`);
|
|
1523
|
+
* }
|
|
1524
|
+
* ```
|
|
1525
|
+
*/
|
|
1526
|
+
async listMCPTools() {
|
|
1527
|
+
this.logger.debug("listMCPTools");
|
|
1528
|
+
const response = await fetch(`${this.baseUrl}/api/mcp`, {
|
|
1529
|
+
method: "POST",
|
|
1530
|
+
headers: { "Content-Type": "application/json" },
|
|
1531
|
+
body: JSON.stringify({
|
|
1532
|
+
jsonrpc: "2.0",
|
|
1533
|
+
method: "tools/list",
|
|
1534
|
+
id: Date.now()
|
|
1535
|
+
})
|
|
1536
|
+
});
|
|
1537
|
+
if (!response.ok) {
|
|
1538
|
+
throw new MixrPayError(`Failed to list MCP tools: ${response.status}`);
|
|
1539
|
+
}
|
|
1540
|
+
const result = await response.json();
|
|
1541
|
+
if (result.error) {
|
|
1542
|
+
throw new MixrPayError(result.error.message || "Failed to list MCP tools");
|
|
1543
|
+
}
|
|
1544
|
+
return (result.result?.tools || []).map((tool) => ({
|
|
1545
|
+
name: tool.name,
|
|
1546
|
+
description: tool.description,
|
|
1547
|
+
inputSchema: tool.inputSchema,
|
|
1548
|
+
priceUsd: tool["x-mixrpay"]?.priceUsd || 0,
|
|
1549
|
+
merchantName: tool["x-mixrpay"]?.merchantName,
|
|
1550
|
+
merchantSlug: tool["x-mixrpay"]?.merchantSlug,
|
|
1551
|
+
verified: tool["x-mixrpay"]?.verified || false
|
|
1552
|
+
}));
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Call an MCP tool with wallet authentication (direct pay per call).
|
|
1556
|
+
*
|
|
1557
|
+
* This method signs a fresh auth message for each call, charging
|
|
1558
|
+
* directly from your wallet balance without needing a session.
|
|
1559
|
+
*
|
|
1560
|
+
* @param toolName - The tool name in format "merchant/tool"
|
|
1561
|
+
* @param args - Arguments to pass to the tool
|
|
1562
|
+
* @returns Tool execution result
|
|
1563
|
+
*
|
|
1564
|
+
* @example
|
|
1565
|
+
* ```typescript
|
|
1566
|
+
* const result = await wallet.callMCPTool('firecrawl/scrape', {
|
|
1567
|
+
* url: 'https://example.com',
|
|
1568
|
+
* });
|
|
1569
|
+
* console.log(result.data);
|
|
1570
|
+
* console.log(`Charged: $${result.chargedUsd}`);
|
|
1571
|
+
* ```
|
|
1572
|
+
*/
|
|
1573
|
+
async callMCPTool(toolName, args = {}) {
|
|
1574
|
+
this.logger.debug("callMCPTool", { toolName, args });
|
|
1575
|
+
const authHeaders = await this.getMCPAuthHeaders();
|
|
1576
|
+
const response = await fetch(`${this.baseUrl}/api/mcp`, {
|
|
1577
|
+
method: "POST",
|
|
1578
|
+
headers: {
|
|
1579
|
+
"Content-Type": "application/json",
|
|
1580
|
+
...authHeaders
|
|
1581
|
+
},
|
|
1582
|
+
body: JSON.stringify({
|
|
1583
|
+
jsonrpc: "2.0",
|
|
1584
|
+
method: "tools/call",
|
|
1585
|
+
params: { name: toolName, arguments: args },
|
|
1586
|
+
id: Date.now()
|
|
1587
|
+
})
|
|
1588
|
+
});
|
|
1589
|
+
const result = await response.json();
|
|
1590
|
+
if (result.error) {
|
|
1591
|
+
throw new MixrPayError(result.error.message || "MCP tool call failed");
|
|
1592
|
+
}
|
|
1593
|
+
const content = result.result?.content?.[0];
|
|
1594
|
+
const data = content?.text ? JSON.parse(content.text) : null;
|
|
1595
|
+
const mixrpay = result.result?._mixrpay || {};
|
|
1596
|
+
if (mixrpay.chargedUsd) {
|
|
1597
|
+
const payment = {
|
|
1598
|
+
amountUsd: mixrpay.chargedUsd,
|
|
1599
|
+
recipient: toolName.split("/")[0] || toolName,
|
|
1600
|
+
txHash: mixrpay.txHash,
|
|
1601
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1602
|
+
description: `MCP: ${toolName}`,
|
|
1603
|
+
url: `${this.baseUrl}/api/mcp`
|
|
1604
|
+
};
|
|
1605
|
+
this.payments.push(payment);
|
|
1606
|
+
this.totalSpentUsd += mixrpay.chargedUsd;
|
|
1607
|
+
this.logger.payment(mixrpay.chargedUsd, toolName, "MCP call");
|
|
1608
|
+
if (this.onPayment) {
|
|
1609
|
+
this.onPayment(payment);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
return {
|
|
1613
|
+
data,
|
|
1614
|
+
chargedUsd: mixrpay.chargedUsd || 0,
|
|
1615
|
+
txHash: mixrpay.txHash,
|
|
1616
|
+
latencyMs: mixrpay.latencyMs
|
|
1617
|
+
};
|
|
1618
|
+
}
|
|
1619
|
+
// ===========================================================================
|
|
1620
|
+
// Agent Runtime API
|
|
1621
|
+
// ===========================================================================
|
|
1622
|
+
/**
|
|
1623
|
+
* Run an AI agent with LLM and tool execution.
|
|
1624
|
+
*
|
|
1625
|
+
* This method orchestrates a full agentic loop:
|
|
1626
|
+
* - Multi-turn reasoning with LLM
|
|
1627
|
+
* - Automatic tool execution
|
|
1628
|
+
* - Bundled billing (single charge at end)
|
|
1629
|
+
* - Optional streaming via SSE
|
|
1630
|
+
*
|
|
1631
|
+
* @param options - Agent run options
|
|
1632
|
+
* @returns Agent run result with response and cost breakdown
|
|
1633
|
+
*
|
|
1634
|
+
* @example Basic usage
|
|
1635
|
+
* ```typescript
|
|
1636
|
+
* const result = await wallet.runAgent({
|
|
1637
|
+
* sessionId: 'sess_abc123',
|
|
1638
|
+
* messages: [{ role: 'user', content: 'Find AI startups in SF' }],
|
|
1639
|
+
* });
|
|
1640
|
+
*
|
|
1641
|
+
* console.log(result.response);
|
|
1642
|
+
* console.log(`Cost: $${result.cost.totalUsd.toFixed(4)}`);
|
|
1643
|
+
* ```
|
|
1644
|
+
*
|
|
1645
|
+
* @example With custom config
|
|
1646
|
+
* ```typescript
|
|
1647
|
+
* const result = await wallet.runAgent({
|
|
1648
|
+
* sessionId: 'sess_abc123',
|
|
1649
|
+
* messages: [{ role: 'user', content: 'Research quantum computing' }],
|
|
1650
|
+
* config: {
|
|
1651
|
+
* model: 'gpt-4o',
|
|
1652
|
+
* maxIterations: 15,
|
|
1653
|
+
* tools: ['platform/exa-search', 'platform/firecrawl-scrape'],
|
|
1654
|
+
* systemPrompt: 'You are a research assistant.',
|
|
1655
|
+
* },
|
|
1656
|
+
* });
|
|
1657
|
+
* ```
|
|
1658
|
+
*
|
|
1659
|
+
* @example With streaming
|
|
1660
|
+
* ```typescript
|
|
1661
|
+
* await wallet.runAgent({
|
|
1662
|
+
* sessionId: 'sess_abc123',
|
|
1663
|
+
* messages: [{ role: 'user', content: 'Analyze this company' }],
|
|
1664
|
+
* stream: true,
|
|
1665
|
+
* onEvent: (event) => {
|
|
1666
|
+
* if (event.type === 'llm_chunk') {
|
|
1667
|
+
* process.stdout.write(event.delta);
|
|
1668
|
+
* } else if (event.type === 'tool_call') {
|
|
1669
|
+
* console.log(`Calling tool: ${event.tool}`);
|
|
1670
|
+
* }
|
|
1671
|
+
* },
|
|
1672
|
+
* });
|
|
1673
|
+
* ```
|
|
1674
|
+
*/
|
|
1675
|
+
async runAgent(options) {
|
|
1676
|
+
const {
|
|
1677
|
+
sessionId,
|
|
1678
|
+
messages,
|
|
1679
|
+
config = {},
|
|
1680
|
+
stream = false,
|
|
1681
|
+
idempotencyKey,
|
|
1682
|
+
onEvent
|
|
1683
|
+
} = options;
|
|
1684
|
+
this.logger.debug("runAgent", { sessionId, messageCount: messages.length, config, stream });
|
|
1685
|
+
const body = {
|
|
1686
|
+
session_id: sessionId,
|
|
1687
|
+
messages: messages.map((m) => ({ role: m.role, content: m.content })),
|
|
1688
|
+
config: {
|
|
1689
|
+
model: config.model,
|
|
1690
|
+
max_iterations: config.maxIterations,
|
|
1691
|
+
tools: config.tools,
|
|
1692
|
+
system_prompt: config.systemPrompt
|
|
1693
|
+
},
|
|
1694
|
+
stream,
|
|
1695
|
+
idempotency_key: idempotencyKey
|
|
1696
|
+
};
|
|
1697
|
+
const AGENT_RUN_TIMEOUT = 18e4;
|
|
1698
|
+
if (!stream) {
|
|
1699
|
+
const response = await fetch(`${this.baseUrl}/api/v2/agent/run`, {
|
|
1700
|
+
method: "POST",
|
|
1701
|
+
headers: {
|
|
1702
|
+
"Content-Type": "application/json",
|
|
1703
|
+
"X-Mixr-Session": sessionId
|
|
1704
|
+
},
|
|
1705
|
+
body: JSON.stringify(body),
|
|
1706
|
+
signal: AbortSignal.timeout(AGENT_RUN_TIMEOUT)
|
|
1707
|
+
});
|
|
1708
|
+
if (!response.ok) {
|
|
1709
|
+
const error = await response.json().catch(() => ({}));
|
|
1710
|
+
throw new MixrPayError(error.error || `Agent run failed: ${response.status}`);
|
|
1711
|
+
}
|
|
1712
|
+
const data = await response.json();
|
|
1713
|
+
if (data.cost?.total_usd > 0) {
|
|
1714
|
+
const payment = {
|
|
1715
|
+
amountUsd: data.cost.total_usd,
|
|
1716
|
+
recipient: "mixrpay-agent-run",
|
|
1717
|
+
txHash: data.tx_hash,
|
|
1718
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1719
|
+
description: `Agent run: ${data.run_id}`,
|
|
1720
|
+
url: `${this.baseUrl}/api/v2/agent/run`
|
|
1721
|
+
};
|
|
1722
|
+
this.payments.push(payment);
|
|
1723
|
+
this.totalSpentUsd += data.cost.total_usd;
|
|
1724
|
+
this.logger.payment(data.cost.total_usd, "agent-run", data.run_id);
|
|
1725
|
+
if (this.onPayment) {
|
|
1726
|
+
this.onPayment(payment);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
return {
|
|
1730
|
+
runId: data.run_id,
|
|
1731
|
+
status: data.status,
|
|
1732
|
+
response: data.response,
|
|
1733
|
+
iterations: data.iterations,
|
|
1734
|
+
toolsUsed: data.tools_used,
|
|
1735
|
+
cost: {
|
|
1736
|
+
llmUsd: data.cost.llm_usd,
|
|
1737
|
+
toolsUsd: data.cost.tools_usd,
|
|
1738
|
+
totalUsd: data.cost.total_usd
|
|
1739
|
+
},
|
|
1740
|
+
tokens: data.tokens,
|
|
1741
|
+
sessionRemainingUsd: data.session_remaining_usd,
|
|
1742
|
+
txHash: data.tx_hash
|
|
1743
|
+
};
|
|
1744
|
+
}
|
|
1745
|
+
return this.runAgentStreaming(sessionId, body, onEvent);
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Internal: Handle streaming agent run via SSE
|
|
1749
|
+
*/
|
|
1750
|
+
async runAgentStreaming(sessionId, body, onEvent) {
|
|
1751
|
+
const STREAMING_TIMEOUT = 3e5;
|
|
1752
|
+
const response = await fetch(`${this.baseUrl}/api/v2/agent/run`, {
|
|
1753
|
+
method: "POST",
|
|
1754
|
+
headers: {
|
|
1755
|
+
"Content-Type": "application/json",
|
|
1756
|
+
"X-Mixr-Session": sessionId
|
|
1757
|
+
},
|
|
1758
|
+
body: JSON.stringify(body),
|
|
1759
|
+
signal: AbortSignal.timeout(STREAMING_TIMEOUT)
|
|
1760
|
+
});
|
|
1761
|
+
if (!response.ok) {
|
|
1762
|
+
const error = await response.json().catch(() => ({}));
|
|
1763
|
+
throw new MixrPayError(error.error || `Agent run failed: ${response.status}`);
|
|
1764
|
+
}
|
|
1765
|
+
const reader = response.body?.getReader();
|
|
1766
|
+
if (!reader) {
|
|
1767
|
+
throw new MixrPayError("No response body for streaming");
|
|
1768
|
+
}
|
|
1769
|
+
const decoder = new TextDecoder();
|
|
1770
|
+
let buffer = "";
|
|
1771
|
+
let result = null;
|
|
1772
|
+
while (true) {
|
|
1773
|
+
const { done, value } = await reader.read();
|
|
1774
|
+
if (done) break;
|
|
1775
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1776
|
+
const lines = buffer.split("\n");
|
|
1777
|
+
buffer = lines.pop() || "";
|
|
1778
|
+
let currentEvent = "";
|
|
1779
|
+
for (const line of lines) {
|
|
1780
|
+
if (line.startsWith("event: ")) {
|
|
1781
|
+
currentEvent = line.slice(7).trim();
|
|
1782
|
+
} else if (line.startsWith("data: ") && currentEvent) {
|
|
1783
|
+
try {
|
|
1784
|
+
const data = JSON.parse(line.slice(6));
|
|
1785
|
+
const event = this.parseSSEEvent(currentEvent, data);
|
|
1786
|
+
if (event) {
|
|
1787
|
+
onEvent?.(event);
|
|
1788
|
+
if (currentEvent === "complete") {
|
|
1789
|
+
result = {
|
|
1790
|
+
runId: data.run_id,
|
|
1791
|
+
status: "completed",
|
|
1792
|
+
response: data.response,
|
|
1793
|
+
iterations: data.iterations,
|
|
1794
|
+
toolsUsed: data.tools_used,
|
|
1795
|
+
cost: {
|
|
1796
|
+
llmUsd: 0,
|
|
1797
|
+
// Not provided in streaming complete
|
|
1798
|
+
toolsUsd: 0,
|
|
1799
|
+
totalUsd: data.total_cost_usd
|
|
1800
|
+
},
|
|
1801
|
+
tokens: { prompt: 0, completion: 0 },
|
|
1802
|
+
sessionRemainingUsd: 0,
|
|
1803
|
+
txHash: data.tx_hash
|
|
1804
|
+
};
|
|
1805
|
+
if (data.total_cost_usd > 0) {
|
|
1806
|
+
const payment = {
|
|
1807
|
+
amountUsd: data.total_cost_usd,
|
|
1808
|
+
recipient: "mixrpay-agent-run",
|
|
1809
|
+
txHash: data.tx_hash,
|
|
1810
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1811
|
+
description: `Agent run: ${data.run_id}`,
|
|
1812
|
+
url: `${this.baseUrl}/api/v2/agent/run`
|
|
1813
|
+
};
|
|
1814
|
+
this.payments.push(payment);
|
|
1815
|
+
this.totalSpentUsd += data.total_cost_usd;
|
|
1816
|
+
if (this.onPayment) {
|
|
1817
|
+
this.onPayment(payment);
|
|
1818
|
+
}
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
if (currentEvent === "error") {
|
|
1822
|
+
throw new MixrPayError(data.error || "Agent run failed");
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
} catch (e) {
|
|
1826
|
+
if (e instanceof MixrPayError) throw e;
|
|
1827
|
+
this.logger.warn("Failed to parse SSE event:", e);
|
|
1828
|
+
}
|
|
1829
|
+
currentEvent = "";
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
if (!result) {
|
|
1834
|
+
throw new MixrPayError("Agent run completed without final result");
|
|
1835
|
+
}
|
|
1836
|
+
return result;
|
|
1837
|
+
}
|
|
1838
|
+
/**
|
|
1839
|
+
* Internal: Parse SSE event into typed event object
|
|
1840
|
+
*/
|
|
1841
|
+
parseSSEEvent(eventType, data) {
|
|
1842
|
+
switch (eventType) {
|
|
1843
|
+
case "run_start":
|
|
1844
|
+
return { type: "run_start", runId: data.run_id };
|
|
1845
|
+
case "iteration_start":
|
|
1846
|
+
return { type: "iteration_start", iteration: data.iteration };
|
|
1847
|
+
case "llm_chunk":
|
|
1848
|
+
return { type: "llm_chunk", delta: data.delta };
|
|
1849
|
+
case "tool_call":
|
|
1850
|
+
return { type: "tool_call", tool: data.tool, arguments: data.arguments };
|
|
1851
|
+
case "tool_result":
|
|
1852
|
+
return {
|
|
1853
|
+
type: "tool_result",
|
|
1854
|
+
tool: data.tool,
|
|
1855
|
+
success: data.success,
|
|
1856
|
+
costUsd: data.cost_usd,
|
|
1857
|
+
error: data.error
|
|
1858
|
+
};
|
|
1859
|
+
case "iteration_complete":
|
|
1860
|
+
return {
|
|
1861
|
+
type: "iteration_complete",
|
|
1862
|
+
iteration: data.iteration,
|
|
1863
|
+
tokens: data.tokens,
|
|
1864
|
+
costUsd: data.cost_usd
|
|
1865
|
+
};
|
|
1866
|
+
case "complete":
|
|
1867
|
+
return {
|
|
1868
|
+
type: "complete",
|
|
1869
|
+
runId: data.run_id,
|
|
1870
|
+
response: data.response,
|
|
1871
|
+
totalCostUsd: data.total_cost_usd,
|
|
1872
|
+
txHash: data.tx_hash,
|
|
1873
|
+
iterations: data.iterations,
|
|
1874
|
+
toolsUsed: data.tools_used
|
|
1875
|
+
};
|
|
1876
|
+
case "error":
|
|
1877
|
+
return {
|
|
1878
|
+
type: "error",
|
|
1879
|
+
error: data.error,
|
|
1880
|
+
partialCostUsd: data.partial_cost_usd
|
|
1881
|
+
};
|
|
1882
|
+
default:
|
|
1883
|
+
return null;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
/**
|
|
1887
|
+
* Get the status of an agent run by ID.
|
|
1888
|
+
*
|
|
1889
|
+
* @param runId - The agent run ID
|
|
1890
|
+
* @param sessionId - The session ID (for authentication)
|
|
1891
|
+
* @returns Agent run status and results
|
|
1892
|
+
*
|
|
1893
|
+
* @example
|
|
1894
|
+
* ```typescript
|
|
1895
|
+
* const status = await wallet.getAgentRunStatus('run_abc123', 'sess_xyz789');
|
|
1896
|
+
* console.log(`Status: ${status.status}`);
|
|
1897
|
+
* if (status.status === 'completed') {
|
|
1898
|
+
* console.log(status.response);
|
|
1899
|
+
* }
|
|
1900
|
+
* ```
|
|
1901
|
+
*/
|
|
1902
|
+
async getAgentRunStatus(runId, sessionId) {
|
|
1903
|
+
this.logger.debug("getAgentRunStatus", { runId, sessionId });
|
|
1904
|
+
const response = await fetch(`${this.baseUrl}/api/v2/agent/run/${runId}`, {
|
|
1905
|
+
headers: {
|
|
1906
|
+
"X-Mixr-Session": sessionId
|
|
1907
|
+
}
|
|
1908
|
+
});
|
|
1909
|
+
if (!response.ok) {
|
|
1910
|
+
const error = await response.json().catch(() => ({}));
|
|
1911
|
+
throw new MixrPayError(error.error || `Failed to get run status: ${response.status}`);
|
|
1912
|
+
}
|
|
1913
|
+
const data = await response.json();
|
|
1914
|
+
return {
|
|
1915
|
+
runId: data.run_id,
|
|
1916
|
+
status: data.status,
|
|
1917
|
+
response: data.response,
|
|
1918
|
+
iterations: data.iterations,
|
|
1919
|
+
toolsUsed: data.tools_used,
|
|
1920
|
+
cost: {
|
|
1921
|
+
llmUsd: data.cost.llm_usd,
|
|
1922
|
+
toolsUsd: data.cost.tools_usd,
|
|
1923
|
+
totalUsd: data.cost.total_usd
|
|
1924
|
+
},
|
|
1925
|
+
tokens: data.tokens,
|
|
1926
|
+
txHash: data.tx_hash,
|
|
1927
|
+
error: data.error,
|
|
1928
|
+
startedAt: new Date(data.started_at),
|
|
1929
|
+
completedAt: data.completed_at ? new Date(data.completed_at) : void 0
|
|
1930
|
+
};
|
|
1931
|
+
}
|
|
1932
|
+
/**
|
|
1933
|
+
* Call an MCP tool using session authorization (pre-authorized spending limit).
|
|
1934
|
+
*
|
|
1935
|
+
* Use this when you've already created a session with the tool provider
|
|
1936
|
+
* and want to use that spending limit instead of direct wallet charges.
|
|
1937
|
+
*
|
|
1938
|
+
* @param sessionId - The session ID for the tool provider
|
|
1939
|
+
* @param toolName - The tool name in format "merchant/tool"
|
|
1940
|
+
* @param args - Arguments to pass to the tool
|
|
1941
|
+
* @returns Tool execution result
|
|
1942
|
+
*
|
|
1943
|
+
* @example
|
|
1944
|
+
* ```typescript
|
|
1945
|
+
* // Create session with provider first
|
|
1946
|
+
* const session = await wallet.getOrCreateSession({
|
|
1947
|
+
* merchantPublicKey: 'pk_live_firecrawl_...',
|
|
1948
|
+
* spendingLimitUsd: 50,
|
|
1949
|
+
* });
|
|
1950
|
+
*
|
|
1951
|
+
* // Use session for multiple calls
|
|
1952
|
+
* const result = await wallet.callMCPToolWithSession(
|
|
1953
|
+
* session.id,
|
|
1954
|
+
* 'firecrawl/scrape',
|
|
1955
|
+
* { url: 'https://example.com' }
|
|
1956
|
+
* );
|
|
1957
|
+
* ```
|
|
1958
|
+
*/
|
|
1959
|
+
async callMCPToolWithSession(sessionId, toolName, args = {}) {
|
|
1960
|
+
this.logger.debug("callMCPToolWithSession", { sessionId, toolName, args });
|
|
1961
|
+
const response = await fetch(`${this.baseUrl}/api/mcp`, {
|
|
1962
|
+
method: "POST",
|
|
1963
|
+
headers: {
|
|
1964
|
+
"Content-Type": "application/json",
|
|
1965
|
+
"X-Mixr-Session": sessionId
|
|
1966
|
+
},
|
|
1967
|
+
body: JSON.stringify({
|
|
1968
|
+
jsonrpc: "2.0",
|
|
1969
|
+
method: "tools/call",
|
|
1970
|
+
params: { name: toolName, arguments: args },
|
|
1971
|
+
id: Date.now()
|
|
1972
|
+
})
|
|
1973
|
+
});
|
|
1974
|
+
const result = await response.json();
|
|
1975
|
+
if (result.error) {
|
|
1976
|
+
throw new MixrPayError(result.error.message || "MCP tool call failed");
|
|
1977
|
+
}
|
|
1978
|
+
const content = result.result?.content?.[0];
|
|
1979
|
+
const data = content?.text ? JSON.parse(content.text) : null;
|
|
1980
|
+
const mixrpay = result.result?._mixrpay || {};
|
|
1981
|
+
if (mixrpay.chargedUsd) {
|
|
1982
|
+
const payment = {
|
|
1983
|
+
amountUsd: mixrpay.chargedUsd,
|
|
1984
|
+
recipient: toolName.split("/")[0] || toolName,
|
|
1985
|
+
txHash: mixrpay.txHash,
|
|
1986
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
1987
|
+
description: `MCP: ${toolName}`,
|
|
1988
|
+
url: `${this.baseUrl}/api/mcp`
|
|
1989
|
+
};
|
|
1990
|
+
this.payments.push(payment);
|
|
1991
|
+
this.totalSpentUsd += mixrpay.chargedUsd;
|
|
1992
|
+
this.logger.payment(mixrpay.chargedUsd, toolName, "MCP call (session)");
|
|
1993
|
+
if (this.onPayment) {
|
|
1994
|
+
this.onPayment(payment);
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
return {
|
|
1998
|
+
data,
|
|
1999
|
+
chargedUsd: mixrpay.chargedUsd || 0,
|
|
2000
|
+
txHash: mixrpay.txHash,
|
|
2001
|
+
latencyMs: mixrpay.latencyMs
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
1470
2004
|
};
|
|
1471
2005
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1472
2006
|
0 && (module.exports = {
|