@agentic-trust/8004-ext-sdk
Version:
ERC-8004 Agentic Trust SDK - A TypeScript SDK for managing AI agents with ENS integration, identity management, and reputation systems
1,087 lines • 40 kB
JavaScript
/**
* AI Agent Discovery Client
*
* Fronts for discovery-index GraphQL requests to the indexer
* Provides a clean interface for querying agent data
*/
import { GraphQLClient } from 'graphql-request';
const INTROSPECTION_QUERY = `
query SearchCapabilities {
__schema {
queryType {
fields {
name
args {
name
type {
...TypeRef
}
}
type {
...TypeRef
}
}
}
}
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
`;
const TYPE_FIELDS_QUERY = `
query TypeFields($name: String!) {
__type(name: $name) {
fields {
name
type {
...TypeRef
}
}
}
}
fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
`;
function unwrapType(type) {
let current = type;
while (current && (current.kind === 'NON_NULL' || current.kind === 'LIST')) {
current = current.ofType ?? null;
}
return current ?? null;
}
function unwrapToTypeName(type) {
const named = unwrapType(type);
return named?.name ?? null;
}
function isNonNull(type) {
return type?.kind === 'NON_NULL';
}
function isListOf(type, expectedName) {
if (!type)
return false;
if (type.kind === 'NON_NULL')
return isListOf(type.ofType, expectedName);
if (type.kind === 'LIST') {
const inner = type.ofType || null;
if (!inner)
return false;
if (inner.kind === 'NON_NULL') {
return isListOf(inner.ofType, expectedName);
}
return inner.kind === 'OBJECT' && inner.name === expectedName;
}
return false;
}
/**
* AI Agent Discovery Client
*
* Provides methods for querying agent data from the indexer
*/
export class AIAgentDiscoveryClient {
client;
config;
searchStrategy;
searchStrategyPromise;
typeFieldsCache = new Map();
constructor(config) {
this.config = config;
const headers = {
'Content-Type': 'application/json',
...(config.headers || {}),
};
if (config.apiKey) {
headers['Authorization'] = `Bearer ${config.apiKey}`;
// Also support API key in header
headers['X-API-Key'] = config.apiKey;
}
this.client = new GraphQLClient(config.endpoint, {
headers,
});
}
normalizeAgent(agent) {
const record = (agent ?? {});
const toOptionalString = (value) => {
if (value === undefined || value === null) {
return undefined;
}
return String(value);
};
const toOptionalStringOrNull = (value) => {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
return String(value);
};
const toOptionalNumber = (value) => {
if (value === undefined || value === null) {
return undefined;
}
const numeric = typeof value === 'number' ? value : Number(value);
return Number.isFinite(numeric) ? numeric : undefined;
};
const toOptionalNumberOrNull = (value) => {
if (value === undefined) {
return undefined;
}
if (value === null) {
return null;
}
const numeric = typeof value === 'number' ? value : Number(value);
return Number.isFinite(numeric) ? numeric : null;
};
const normalized = {
...record,
};
const agentAccount = toOptionalString(record.agentAccount);
if (agentAccount !== undefined) {
normalized.agentAccount = agentAccount;
}
const agentOwner = toOptionalString(record.agentOwner);
if (agentOwner !== undefined) {
normalized.agentOwner = agentOwner;
}
const didIdentity = toOptionalStringOrNull(record.didIdentity);
if (didIdentity !== undefined) {
normalized.didIdentity = didIdentity;
}
const didAccount = toOptionalStringOrNull(record.didAccount);
if (didAccount !== undefined) {
normalized.didAccount = didAccount;
}
const didName = toOptionalStringOrNull(record.didName);
if (didName !== undefined) {
normalized.didName = didName;
}
const tokenUri = toOptionalString(record.tokenUri);
if (tokenUri !== undefined) {
normalized.tokenUri = tokenUri;
}
const validationPendingCount = toOptionalNumberOrNull(record.validationPendingCount);
if (validationPendingCount !== undefined) {
normalized.validationPendingCount = validationPendingCount;
}
const validationCompletedCount = toOptionalNumberOrNull(record.validationCompletedCount);
if (validationCompletedCount !== undefined) {
normalized.validationCompletedCount = validationCompletedCount;
}
const validationRequestedCount = toOptionalNumberOrNull(record.validationRequestedCount);
if (validationRequestedCount !== undefined) {
normalized.validationRequestedCount = validationRequestedCount;
}
const description = toOptionalStringOrNull(record.description);
if (description !== undefined) {
normalized.description = description;
}
const image = toOptionalStringOrNull(record.image);
if (image !== undefined) {
normalized.image = image;
}
const a2aEndpoint = toOptionalStringOrNull(record.a2aEndpoint);
if (a2aEndpoint !== undefined) {
normalized.a2aEndpoint = a2aEndpoint;
}
const ensEndpoint = toOptionalStringOrNull(record.ensEndpoint);
if (ensEndpoint !== undefined) {
normalized.ensEndpoint = ensEndpoint;
}
const agentAccountEndpoint = toOptionalStringOrNull(record.agentAccountEndpoint);
if (agentAccountEndpoint !== undefined) {
normalized.agentAccountEndpoint = agentAccountEndpoint;
}
const supportedTrust = toOptionalString(record.supportedTrust);
if (supportedTrust !== undefined) {
normalized.supportedTrust = supportedTrust;
}
const did = toOptionalStringOrNull(record.did);
if (did !== undefined) {
normalized.did = did;
}
return normalized;
}
/**
* List agents with a deterministic default ordering (agentId DESC).
*
* @param limit - Maximum number of agents to return per page
* @param offset - Number of agents to skip
* @returns List of agents
*/
async listAgents(limit, offset) {
let allAgents = [];
const effectiveLimit = limit ?? 100;
const effectiveOffset = offset ?? 0;
const query = `
query ListAgents($limit: Int, $offset: Int) {
agents(limit: $limit, offset: $offset) {
chainId
agentId
agentAccount
agentOwner
agentName
didIdentity
didAccount
didName
tokenUri
createdAtBlock
createdAtTime
updatedAtTime
type
description
image
a2aEndpoint
ensEndpoint
agentAccountEndpoint
did
mcp
x402support
active
supportedTrust
rawJson
}
}
`;
try {
const data = await this.client.request(query, {
limit: effectiveLimit,
offset: effectiveOffset,
});
const pageAgents = (data.agents || []).map((agent) => this.normalizeAgent(agent));
allAgents = allAgents.concat(pageAgents);
// Apply client-side ordering to ensure deterministic results,
// since the base agents query may not support orderBy/orderDirection
// arguments. Default is agentId DESC for "newest first".
// Default to newest agents first by agentId DESC
allAgents.sort((a, b) => {
const idA = typeof a.agentId === 'number' ? a.agentId : Number(a.agentId ?? 0) || 0;
const idB = typeof b.agentId === 'number' ? b.agentId : Number(b.agentId ?? 0) || 0;
return idB - idA;
});
}
catch (error) {
console.warn('[AIAgentDiscoveryClient.listAgents] Error fetching agents with pagination:', error);
}
return allAgents;
}
async searchAgentsAdvanced(options) {
console.log('>>>>>>>>>>>>>>>>>> searchAgentsAdvanced', options);
const strategy = await this.detectSearchStrategy();
const { query, params, limit, offset } = options;
const trimmedQuery = typeof query === 'string' ? query.trim() : '';
const hasQuery = trimmedQuery.length > 0;
const hasParams = params && Object.keys(params).length > 0;
if (!hasQuery && !hasParams) {
return null;
}
// If no detected strategy (introspection disabled), attempt a direct list-form searchAgents call.
// Only use this fallback if we have a query string, since the GraphQL query requires a non-null query parameter.
// If we only have params but no query, return null to trigger local filtering fallback.
console.log('>>>>>>>>>>>>>>>>>> 012 strategy', strategy);
if (!strategy) {
console.log('>>>>>>>>>>>>>>>>>> 012 hasQuery', hasQuery);
if (hasQuery) {
try {
console.log('>>>>>>>>>>>>>>>>>> 012 trimmedQuery', trimmedQuery);
console.log('>>>>>>>>>>>>>>>>>> 012 limit', limit);
console.log('>>>>>>>>>>>>>>>>>> 012 offset', offset);
console.log('>>>>>>>>>>>>>>>>>> 012 options.orderBy', options.orderBy);
console.log('>>>>>>>>>>>>>>>>>> 012 options.orderDirection', options.orderDirection);
const queryText = `
query SearchAgentsFallback($query: String!, $limit: Int, $offset: Int, $orderBy: String, $orderDirection: String) {
searchAgents(query: $query, limit: $limit, offset: $offset, orderBy: $orderBy, orderDirection: $orderDirection) {
chainId
agentId
agentAccount
agentOwner
agentName
didIdentity
didAccount
didName
tokenUri
createdAtBlock
createdAtTime
updatedAtTime
type
description
image
a2aEndpoint
ensEndpoint
agentAccountEndpoint
did
mcp
x402support
active
supportedTrust
rawJson
}
}
`;
const variables = {
query: trimmedQuery,
limit: typeof limit === 'number' ? limit : undefined,
offset: typeof offset === 'number' ? offset : undefined,
orderBy: options.orderBy,
orderDirection: options.orderDirection,
};
const data = await this.client.request(queryText, variables);
const list = data?.searchAgents;
console.log('>>>>>>>>>>>>>>>>>> 012 list.length', list?.length);
if (list && list.length > 0) {
console.log('>>>>>>>>>>>>>>>>>> 012 First raw agent sample:', JSON.stringify(list[0], null, 2));
}
if (Array.isArray(list)) {
const normalizedList = list
.filter(Boolean)
.map((item) => this.normalizeAgent(item));
// Ensure fallback respects the requested ordering, even if the
// underlying searchAgents resolver uses its own default order.
const orderBy = typeof options.orderBy === 'string' ? options.orderBy.trim() : undefined;
const orderDirectionRaw = typeof options.orderDirection === 'string'
? options.orderDirection.toUpperCase()
: 'DESC';
const orderDirection = orderDirectionRaw === 'DESC' ? 'DESC' : 'ASC';
if (orderBy === 'agentName') {
normalizedList.sort((a, b) => {
const aName = (a.agentName ?? '').toLowerCase();
const bName = (b.agentName ?? '').toLowerCase();
return orderDirection === 'ASC'
? aName.localeCompare(bName)
: bName.localeCompare(aName);
});
}
else if (orderBy === 'agentId') {
normalizedList.sort((a, b) => {
const idA = typeof a.agentId === 'number'
? a.agentId
: Number(a.agentId ?? 0) || 0;
const idB = typeof b.agentId === 'number'
? b.agentId
: Number(b.agentId ?? 0) || 0;
return orderDirection === 'ASC' ? idA - idB : idB - idA;
});
}
else if (orderBy === 'createdAtTime') {
normalizedList.sort((a, b) => {
const tA = typeof a.createdAtTime === 'number'
? a.createdAtTime
: Number(a.createdAtTime ?? 0) || 0;
const tB = typeof b.createdAtTime === 'number'
? b.createdAtTime
: Number(b.createdAtTime ?? 0) || 0;
return orderDirection === 'ASC' ? tA - tB : tB - tA;
});
}
else if (orderBy === 'createdAtBlock') {
normalizedList.sort((a, b) => {
const bA = typeof a.createdAtBlock === 'number'
? a.createdAtBlock
: Number(a.createdAtBlock ?? 0) || 0;
const bB = typeof b.createdAtBlock === 'number'
? b.createdAtBlock
: Number(b.createdAtBlock ?? 0) || 0;
return orderDirection === 'ASC' ? bA - bB : bB - bA;
});
}
else if (orderBy === 'agentOwner') {
normalizedList.sort((a, b) => {
const aOwner = (a.agentOwner ?? '').toLowerCase();
const bOwner = (b.agentOwner ?? '').toLowerCase();
return orderDirection === 'ASC'
? aOwner.localeCompare(bOwner)
: bOwner.localeCompare(aOwner);
});
}
console.log('>>>>>>>>>>>>>>>>>> 345 AdvancedSearch', normalizedList);
return { agents: normalizedList, total: undefined };
}
}
catch (error) {
console.warn('[AIAgentDiscoveryClient] Fallback searchAgents call failed:', error);
}
}
// If no strategy and no query (only params), return null to trigger local filtering fallback
return null;
}
const variables = {};
const variableDefinitions = [];
const argumentAssignments = [];
const agentSelection = `
chainId
agentId
agentAccount
agentOwner
agentName
didIdentity
didAccount
didName
tokenUri
createdAtBlock
createdAtTime
updatedAtTime
type
description
image
a2aEndpoint
ensEndpoint
agentAccountEndpoint
did
mcp
x402support
active
supportedTrust
rawJson
feedbackCount
feedbackAverageScore
validationPendingCount
validationCompletedCount
validationRequestedCount
`;
const addStringArg = (arg, value) => {
if (!arg)
return !value;
if (!value) {
return arg.isNonNull ? false : true;
}
const typeName = arg.typeName ?? 'String';
variableDefinitions.push(`$${arg.name}: ${typeName}${arg.isNonNull ? '!' : ''}`);
argumentAssignments.push(`${arg.name}: $${arg.name}`);
variables[arg.name] = value;
return true;
};
const addInputArg = (arg, value) => {
if (!arg)
return !value;
if (!value || Object.keys(value).length === 0) {
return arg.isNonNull ? false : true;
}
const typeName = arg.typeName ?? 'JSON';
variableDefinitions.push(`$${arg.name}: ${typeName}${arg.isNonNull ? '!' : ''}`);
argumentAssignments.push(`${arg.name}: $${arg.name}`);
variables[arg.name] = value;
return true;
};
const addIntArg = (arg, value) => {
if (!arg)
return;
if (value === undefined || value === null) {
if (arg.isNonNull) {
return;
}
return;
}
const typeName = arg.typeName ?? 'Int';
variableDefinitions.push(`$${arg.name}: ${typeName}${arg.isNonNull ? '!' : ''}`);
argumentAssignments.push(`${arg.name}: $${arg.name}`);
variables[arg.name] = value;
};
if (strategy.kind === 'connection') {
// Add query arg only if we have a query, or if queryArg is optional
// If queryArg is required (non-null) but we don't have a query, only proceed if we have params
const queryArgAdded = addStringArg(strategy.queryArg, hasQuery ? trimmedQuery : undefined);
if (!queryArgAdded && strategy.queryArg?.isNonNull && !hasParams) {
// Required query arg but no query and no params - can't proceed
return null;
}
// Add filter arg if we have params
const filterArgAdded = addInputArg(strategy.filterArg, hasParams ? params : undefined);
if (!filterArgAdded && strategy.filterArg?.isNonNull && !hasQuery) {
// Required filter arg but no params and no query - can't proceed
return null;
}
// If neither query nor params were added, and both are optional, we need at least one
if (!queryArgAdded && !filterArgAdded && (!strategy.queryArg || !strategy.filterArg)) {
return null;
}
addIntArg(strategy.limitArg, typeof limit === 'number' ? limit : undefined);
addIntArg(strategy.offsetArg, typeof offset === 'number' ? offset : undefined);
addStringArg(strategy.orderByArg, options.orderBy);
addStringArg(strategy.orderDirectionArg, options.orderDirection);
if (argumentAssignments.length === 0) {
return null;
}
console.log('>>>>>>>>>>>>>>>>>> AdvancedSearch', variableDefinitions, argumentAssignments);
const queryText = `
query AdvancedSearch(${variableDefinitions.join(', ')}) {
${strategy.fieldName}(${argumentAssignments.join(', ')}) {
${strategy.totalFieldName ? `${strategy.totalFieldName}` : ''}
${strategy.listFieldName} {
chainId
agentId
agentAccount
agentOwner
agentName
didIdentity
didAccount
didName
tokenUri
createdAtBlock
createdAtTime
updatedAtTime
type
description
image
a2aEndpoint
ensEndpoint
agentAccountEndpoint
did
mcp
x402support
active
supportedTrust
rawJson
}
}
}
`;
try {
const data = await this.client.request(queryText, variables);
const node = data?.[strategy.fieldName];
if (!node)
return null;
const list = node?.[strategy.listFieldName];
if (!Array.isArray(list))
return null;
const totalValue = typeof strategy.totalFieldName === 'string' ? node?.[strategy.totalFieldName] : undefined;
console.log('>>>>>>>>>>>>>>>>>> 123 AdvancedSearch', list);
return {
agents: list.filter(Boolean),
total: typeof totalValue === 'number' ? totalValue : undefined,
};
}
catch (error) {
console.warn('[AIAgentDiscoveryClient] Advanced connection search failed:', error);
this.searchStrategy = null;
return null;
}
}
if (strategy.kind === 'list') {
console.log('>>>>>>>>>>>>>>>>>> AdvancedSearchList', variableDefinitions, argumentAssignments);
if (!addStringArg(strategy.queryArg, hasQuery ? trimmedQuery : undefined)) {
return null;
}
addIntArg(strategy.limitArg, typeof limit === 'number' ? limit : undefined);
addIntArg(strategy.offsetArg, typeof offset === 'number' ? offset : undefined);
addStringArg(strategy.orderByArg, options.orderBy);
addStringArg(strategy.orderDirectionArg, options.orderDirection);
if (argumentAssignments.length === 0) {
return null;
}
const queryText = `
query AdvancedSearchList(${variableDefinitions.join(', ')}) {
${strategy.fieldName}(${argumentAssignments.join(', ')}) {
${agentSelection}
}
}
`;
try {
const data = await this.client.request(queryText, variables);
const list = data?.[strategy.fieldName];
if (!Array.isArray(list))
return null;
return {
agents: list.filter(Boolean),
total: undefined,
};
}
catch (error) {
console.warn('[AIAgentDiscoveryClient] Advanced list search failed:', error);
this.searchStrategy = null;
return null;
}
}
return null;
}
/**
* Search agents using the strongly-typed AgentWhereInput / searchAgentsGraph API.
* This is tailored to the indexer schema that exposes AgentWhereInput and
* searchAgentsGraph(where:, first:, skip:, orderBy:, orderDirection:).
*/
async searchAgentsGraph(options) {
const query = `
query SearchAgentsGraph(
$where: AgentWhereInput
$first: Int
$skip: Int
$orderBy: AgentOrderBy
$orderDirection: OrderDirection
) {
searchAgentsGraph(
where: $where
first: $first
skip: $skip
orderBy: $orderBy
orderDirection: $orderDirection
) {
agents {
chainId
agentId
agentAccount
agentOwner
agentName
didIdentity
didAccount
didName
tokenUri
createdAtBlock
createdAtTime
updatedAtTime
type
description
image
a2aEndpoint
ensEndpoint
agentAccountEndpoint
supportedTrust
rawJson
did
mcp
x402support
active
feedbackCount
feedbackAverageScore
validationPendingCount
validationCompletedCount
validationRequestedCount
}
total
hasMore
}
}
`;
// Default ordering when not explicitly provided: newest agents first
// by agentId DESC.
const effectiveOrderBy = options.orderBy ?? 'agentId';
const effectiveOrderDirection = (options.orderDirection ?? 'DESC').toUpperCase() === 'ASC' ? 'ASC' : 'DESC';
const variables = {
where: options.where,
first: typeof options.first === 'number' ? options.first : undefined,
skip: typeof options.skip === 'number' ? options.skip : undefined,
orderBy: effectiveOrderBy,
orderDirection: effectiveOrderDirection,
};
const data = await this.client.request(query, variables);
const result = data.searchAgentsGraph ?? { agents: [], total: 0, hasMore: false };
const agents = (result.agents ?? []).map((agent) => this.normalizeAgent(agent));
return {
agents,
total: typeof result.total === 'number' ? result.total : agents.length,
hasMore: Boolean(result.hasMore),
};
}
async detectSearchStrategy() {
if (this.searchStrategy !== undefined) {
return this.searchStrategy;
}
if (this.searchStrategyPromise) {
return this.searchStrategyPromise;
}
this.searchStrategyPromise = (async () => {
try {
const data = await this.client.request(INTROSPECTION_QUERY);
const fields = data.__schema?.queryType?.fields ?? [];
const candidateNames = ['searchAgentsAdvanced', 'searchAgents'];
for (const candidate of candidateNames) {
const field = fields.find((f) => f.name === candidate);
if (!field)
continue;
const strategy = await this.buildStrategyFromField(field);
if (strategy) {
this.searchStrategy = strategy;
return strategy;
}
}
}
catch (error) {
console.warn('[AIAgentDiscoveryClient] Failed to introspect search capabilities:', error);
}
finally {
this.searchStrategyPromise = undefined;
}
this.searchStrategy = null;
return null;
})();
return this.searchStrategyPromise;
}
async buildStrategyFromField(field) {
const baseReturn = unwrapType(field.type);
if (!baseReturn)
return null;
const limitArg = field.args.find((arg) => arg.name === 'limit') ??
field.args.find((arg) => arg.name === 'first');
const offsetArg = field.args.find((arg) => arg.name === 'offset') ??
field.args.find((arg) => arg.name === 'skip');
const queryArg = field.args.find((arg) => arg.name === 'query') ??
field.args.find((arg) => arg.name === 'term') ??
field.args.find((arg) => arg.name === 'search');
const filterArg = field.args.find((arg) => arg.name === 'params') ??
field.args.find((arg) => arg.name === 'filters');
const orderByArg = field.args.find((arg) => arg.name === 'orderBy');
const orderDirectionArg = field.args.find((arg) => arg.name === 'orderDirection');
if (baseReturn.kind === 'OBJECT' && baseReturn.name) {
const connectionFields = await this.getTypeFields(baseReturn.name);
if (!connectionFields) {
return null;
}
const listField = connectionFields.find((f) => isListOf(f.type, 'Agent'));
if (!listField) {
return null;
}
const totalField = connectionFields.find((f) => f.name === 'total') ??
connectionFields.find((f) => f.name === 'totalCount') ??
connectionFields.find((f) => f.name === 'count');
return {
kind: 'connection',
fieldName: field.name,
listFieldName: listField.name,
totalFieldName: totalField?.name,
queryArg: queryArg
? {
name: queryArg.name,
typeName: unwrapToTypeName(queryArg.type),
isNonNull: isNonNull(queryArg.type),
}
: undefined,
filterArg: filterArg
? {
name: filterArg.name,
typeName: unwrapToTypeName(filterArg.type),
isNonNull: isNonNull(filterArg.type),
}
: undefined,
limitArg: limitArg
? {
name: limitArg.name,
typeName: unwrapToTypeName(limitArg.type),
isNonNull: isNonNull(limitArg.type),
}
: undefined,
offsetArg: offsetArg
? {
name: offsetArg.name,
typeName: unwrapToTypeName(offsetArg.type),
isNonNull: isNonNull(offsetArg.type),
}
: undefined,
orderByArg: orderByArg
? {
name: orderByArg.name,
typeName: unwrapToTypeName(orderByArg.type),
isNonNull: isNonNull(orderByArg.type),
}
: undefined,
orderDirectionArg: orderDirectionArg
? {
name: orderDirectionArg.name,
typeName: unwrapToTypeName(orderDirectionArg.type),
isNonNull: isNonNull(orderDirectionArg.type),
}
: undefined,
};
}
if (isListOf(field.type, 'Agent')) {
return {
kind: 'list',
fieldName: field.name,
queryArg: queryArg
? {
name: queryArg.name,
typeName: unwrapToTypeName(queryArg.type),
isNonNull: isNonNull(queryArg.type),
}
: undefined,
limitArg: limitArg
? {
name: limitArg.name,
typeName: unwrapToTypeName(limitArg.type),
isNonNull: isNonNull(limitArg.type),
}
: undefined,
offsetArg: offsetArg
? {
name: offsetArg.name,
typeName: unwrapToTypeName(offsetArg.type),
isNonNull: isNonNull(offsetArg.type),
}
: undefined,
orderByArg: orderByArg
? {
name: orderByArg.name,
typeName: unwrapToTypeName(orderByArg.type),
isNonNull: isNonNull(orderByArg.type),
}
: undefined,
orderDirectionArg: orderDirectionArg
? {
name: orderDirectionArg.name,
typeName: unwrapToTypeName(orderDirectionArg.type),
isNonNull: isNonNull(orderDirectionArg.type),
}
: undefined,
};
}
return null;
}
async getTypeFields(typeName) {
if (this.typeFieldsCache.has(typeName)) {
return this.typeFieldsCache.get(typeName) ?? null;
}
try {
const data = await this.client.request(TYPE_FIELDS_QUERY, { name: typeName });
const fields = data.__type?.fields ?? null;
this.typeFieldsCache.set(typeName, fields ?? null);
return fields ?? null;
}
catch (error) {
console.warn(`[AIAgentDiscoveryClient] Failed to introspect type fields for ${typeName}:`, error);
this.typeFieldsCache.set(typeName, null);
return null;
}
}
/**
* Get a single agent by ID
* @param chainId - Chain ID (required by schema)
* @param agentId - Agent ID to fetch
* @returns Agent data or null if not found
*/
async getAgent(chainId, agentId) {
const query = `
query GetAgent($chainId: Int!, $agentId: String!) {
agent(chainId: $chainId, agentId: $agentId) {
chainId
agentId
agentAccount
agentOwner
agentName
didIdentity
didAccount
didName
tokenUri
createdAtBlock
createdAtTime
updatedAtTime
type
description
image
a2aEndpoint
ensEndpoint
agentAccountEndpoint
did
mcp
x402support
active
supportedTrust
rawJson
}
}
`;
try {
const data = await this.client.request(query, {
chainId,
agentId: String(agentId),
});
if (!data.agent) {
return null;
}
return this.normalizeAgent(data.agent);
}
catch (error) {
console.error('[AIAgentDiscoveryClient.getAgent] Error fetching agent:', error);
return null;
}
}
async getAgentByName(agentName) {
const query = `
query GetAgentByName($agentName: String!) {
agentByName(agentName: $agentName) {
chainId
agentId
agentAccount
agentOwner
agentName
didIdentity
didAccount
didName
tokenUri
createdAtBlock
createdAtTime
updatedAtTime
type
description
image
a2aEndpoint
ensEndpoint
agentAccountEndpoint
did
mcp
x402support
active
supportedTrust
rawJson
}
}
`;
try {
const data = await this.client.request(query, {
agentName,
});
console.log("*********** AIAgentDiscoveryClient.getAgentByName: data", data);
if (!data.agentByName) {
return null;
}
return this.normalizeAgent(data.agentByName);
}
catch (error) {
console.error('[AIAgentDiscoveryClient.getAgentByName] Error fetching agent:', error);
return null;
}
}
/**
* Search agents by name
* @param searchTerm - Search term to match against agent names
* @param limit - Maximum number of results
* @returns List of matching agents
*/
async searchAgents(searchTerm, limit) {
const query = `
query SearchAgents($searchTerm: String!, $limit: Int) {
agents(searchTerm: $searchTerm, limit: $limit) {
chainId
agentId
agentAccount
agentOwner
agentName
didIdentity
didAccount
didName
tokenUri
createdAtBlock
createdAtTime
updatedAtTime
type
description
image
a2aEndpoint
ensEndpoint
agentAccountEndpoint
did
mcp
x402support
active
supportedTrust
rawJson
}
}
`;
try {
const data = await this.client.request(query, {
searchTerm,
limit: limit || 100,
});
const agents = data.agents || [];
return agents.map((agent) => this.normalizeAgent(agent));
}
catch (error) {
console.error('[AIAgentDiscoveryClient.searchAgents] Error searching agents:', error);
throw error;
}
}
/**
* Refresh/Index an agent in the indexer
* Triggers the indexer to re-index the specified agent
* @param agentId - Agent ID to refresh (required)
* @param chainId - Optional chain ID (if not provided, indexer may use default)
* @param apiKey - Optional API key override (uses config API key if not provided)
* @returns Refresh result with success status and processed chains
*/
async refreshAgent(agentId, chainId, apiKey) {
const mutation = `
mutation IndexAgent($agentId: String!, $chainId: Int) {
indexAgent(agentId: $agentId, chainId: $chainId) {
success
message
processedChains
}
}
`;
const variables = {
agentId: String(agentId),
};
if (chainId !== undefined) {
variables.chainId = chainId;
}
// If API key override is provided, create a temporary client with that key
let clientToUse = this.client;
if (apiKey) {
const headers = {
'Content-Type': 'application/json',
...(this.config.headers || {}),
'Authorization': `Bearer ${apiKey}`,
};
clientToUse = new GraphQLClient(this.config.endpoint, {
headers,
});
}
try {
const data = await clientToUse.request(mutation, variables);
return data.indexAgent;
}
catch (error) {
console.error('[AIAgentDiscoveryClient.refreshAgent] Error refreshing agent:', error);
throw new Error(`Failed to refresh agent: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
}
/**
* Execute a raw GraphQL query
* @param query - GraphQL query string
* @param variables - Query variables
* @returns Query response
*/
async request(query, variables) {
return this.client.request(query, variables);
}
/**
* Execute a raw GraphQL mutation
* @param mutation - GraphQL mutation string
* @param variables - Mutation variables
* @returns Mutation response
*/
async mutate(mutation, variables) {
return this.client.request(mutation, variables);
}
/**
* Get the underlying GraphQLClient instance
* @returns The GraphQLClient instance
*/
getClient() {
return this.client;
}
}
//# sourceMappingURL=AIAgentDiscoveryClient.js.map