Skip to content
Open
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
5 changes: 5 additions & 0 deletions packages/ai-controllers/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- `AiDigestService.searchDigest` now uses the universal `asset` query parameter instead of the previous `caipAssetType` / `hlPerpsMarket` branching logic. The public TypeScript API is unchanged; any identifier (CAIP-19, ticker, name, perps market id) can be passed as before ([#8263](https://github.com/MetaMask/core/pull/8263)).
- `RelatedAsset.hlPerpsMarket` now covers all HyperLiquid market identifiers — both regular crypto tokens (`BTC`, `ETH`) and purely synthetic perps assets (`xyz:TSLA`). No separate field is needed; clients use `caip19` presence to decide the icon resolution strategy ([#8263](https://github.com/MetaMask/core/pull/8263)).

## [0.4.0]

### Added
Expand Down
14 changes: 7 additions & 7 deletions packages/ai-controllers/src/AiDigestService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('AiDigestService', () => {
],
};

it('fetches market insights from API using caipAssetType for CAIP-19 identifiers', async () => {
it('fetches market insights using universal asset= param for CAIP-19 identifiers', async () => {
mockFetch.mockResolvedValue({
ok: true,
status: 200,
Expand All @@ -69,11 +69,11 @@ describe('AiDigestService', () => {

expect(result).toStrictEqual(mockMarketInsightsReport);
expect(mockFetch).toHaveBeenCalledWith(
'http://test.com/api/v1/asset-summary?caipAssetType=eip155%3A1%2Ferc20%3A0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
'http://test.com/api/v1/asset-summary?asset=eip155%3A1%2Ferc20%3A0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
);
});

it('fetches market insights from API using hlPerpsMarket for perps symbols', async () => {
it('fetches market insights using universal asset= param for ticker symbols', async () => {
mockFetch.mockResolvedValue({
ok: true,
status: 200,
Expand All @@ -87,7 +87,7 @@ describe('AiDigestService', () => {

expect(result).toStrictEqual(mockMarketInsightsReport);
expect(mockFetch).toHaveBeenCalledWith(
'http://test.com/api/v1/asset-summary?hlPerpsMarket=ETH',
'http://test.com/api/v1/asset-summary?asset=ETH',
);
});

Expand All @@ -104,17 +104,17 @@ describe('AiDigestService', () => {
await service.searchDigest('xyz:TSLA');

expect(mockFetch).toHaveBeenCalledWith(
'http://test.com/api/v1/asset-summary?hlPerpsMarket=xyz%3ATSLA',
'http://test.com/api/v1/asset-summary?asset=xyz%3ATSLA',
);
});

it('accepts digest envelope responses', async () => {
it('accepts summary envelope responses', async () => {
mockFetch.mockResolvedValue({
ok: true,
status: 200,
json: () =>
Promise.resolve({
digest: mockMarketInsightsReport,
summary: mockMarketInsightsReport,
}),
});

Expand Down
27 changes: 12 additions & 15 deletions packages/ai-controllers/src/AiDigestService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
string,
type as structType,
} from '@metamask/superstruct';
import { isCaipAssetType } from '@metamask/utils';

import { AiDigestControllerErrorMessage } from './ai-digest-constants';
import type {
Expand Down Expand Up @@ -79,8 +78,8 @@ const MarketInsightsReportStruct = structType({
metadata: optional(array(AIResponseMetadataStruct)),
});

const MarketInsightsDigestEnvelopeStruct = structType({
digest: MarketInsightsReportStruct,
const MarketInsightsSummaryEnvelopeStruct = structType({
summary: MarketInsightsReportStruct,
});

// Market Overview structs
Expand Down Expand Up @@ -132,8 +131,8 @@ const getNormalizedMarketInsightsReport = (
return value;
}

if (is(value, MarketInsightsDigestEnvelopeStruct)) {
return value.digest;
if (is(value, MarketInsightsSummaryEnvelopeStruct)) {
return value.summary;
}

return null;
Expand Down Expand Up @@ -178,23 +177,21 @@ export class AiDigestService implements DigestService {
/**
* Search for market insights by asset identifier.
*
* Accepts either a CAIP-19 asset type (e.g. `eip155:1/slip44:60`) or a perps
* market symbol (e.g. `ETH`). The query parameter is chosen automatically:
* - CAIP-19 identifiers use `caipAssetType`
* - Perps market symbols use `hlPerpsMarket`
* Accepts any identifier the API understands (CAIP-19 asset type, ticker
* symbol, asset name, HyperLiquid perps market id, etc.) and forwards it
* unchanged via the universal `asset` query parameter.
*
* @param assetIdentifier - The asset identifier (CAIP-19 ID or perps market symbol).
* Calls `GET ${baseUrl}/asset-summary?asset=<assetIdentifier>`.
*
* @param assetIdentifier - The asset identifier (e.g. `eip155:1/slip44:60`,
* `ETH`, `Bitcoin`, `xyz:TSLA`).
* @returns The market insights report, or `null` if none exists (404).
*/
async searchDigest(
assetIdentifier: string,
): Promise<MarketInsightsReport | null> {
const queryParam = isCaipAssetType(assetIdentifier)
? `caipAssetType=${encodeURIComponent(assetIdentifier)}`
: `hlPerpsMarket=${encodeURIComponent(assetIdentifier)}`;

const response = await fetch(
`${this.#baseUrl}/asset-summary?${queryParam}`,
`${this.#baseUrl}/asset-summary?asset=${encodeURIComponent(assetIdentifier)}`,
);

if (response.status === 404) {
Expand Down
20 changes: 12 additions & 8 deletions packages/ai-controllers/src/ai-digest-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export type MarketInsightsTrend = {

/**
* AI-generated market insights report for a crypto asset.
* Returned by `GET /asset-summary?caipAssetType=<caip19Id>` or `GET /asset-summary?hlPerpsMarket=<symbol>`.
* Returned by `GET /asset-summary?asset=<identifier>`.
*/
export type MarketInsightsReport = {
/** API version */
Expand Down Expand Up @@ -138,7 +138,12 @@ export type RelatedAsset = {
caip19: string[];
/** Canonical source asset identifier (e.g. "bitcoin") */
sourceAssetId: string;
/** Optional Hyperliquid perps market symbol (e.g. "BTC") */
/**
* Optional HyperLiquid market identifier for this asset (e.g. `BTC`, `ETH`,
* `xyz:TSLA`). Covers both regular crypto tokens that trade on HyperLiquid
* and purely synthetic perps assets. Use this to resolve Perps icon URLs via
* `getAssetIconUrls` on clients when `caip19` is empty.
*/
hlPerpsMarket?: string;
};

Expand Down Expand Up @@ -188,14 +193,13 @@ export type DigestService = {
/**
* Search for market insights by asset identifier.
*
* Accepts either a CAIP-19 asset type (e.g. `eip155:1/slip44:60`) or a perps
* market symbol (e.g. `ETH`). The implementation is responsible for choosing
* the correct query parameter (`caipAssetType` vs `hlPerpsMarket`).
* Accepts any identifier the API understands — CAIP-19 asset type
* (e.g. `eip155:1/slip44:60`), ticker symbol (e.g. `ETH`), asset name
* (e.g. `Bitcoin`), or HyperLiquid perps market id (e.g. `xyz:TSLA`).
*
* Calls `GET /asset-summary?caipAssetType=<assetIdentifier>` for CAIP-19 IDs,
* or `GET /asset-summary?hlPerpsMarket=<assetIdentifier>` for perps symbols.
* Calls `GET /asset-summary?asset=<assetIdentifier>`.
*
* @param assetIdentifier - The asset identifier (CAIP-19 ID or perps market symbol).
* @param assetIdentifier - The asset identifier.
* @returns The market insights report, or `null` if no insights exist (404).
*/
searchDigest(assetIdentifier: string): Promise<MarketInsightsReport | null>;
Expand Down
Loading