Skip to main content
Glama
agentstatus.ts3.51 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import type { WithId } from '@medplum/core'; import { allOk, badRequest, isOperationOutcome, normalizeErrorString } from '@medplum/core'; import type { FhirRequest, FhirResponse } from '@medplum/fhir-router'; import type { Agent, OperationDefinition, OperationOutcome, Parameters } from '@medplum/fhirtypes'; import type { AgentInfo } from '../../agent/utils'; import { AgentConnectionState } from '../../agent/utils'; import { getAuthenticatedContext } from '../../context'; import { getRedis } from '../../redis'; import { getAgentForRequest } from './utils/agentutils'; import { buildOutputParameters } from './utils/parameters'; export const operation: OperationDefinition = { resourceType: 'OperationDefinition', name: 'agent-status', status: 'active', kind: 'operation', code: 'status', experimental: true, resource: ['Agent'], system: false, type: false, instance: true, parameter: [ { use: 'out', name: 'status', type: 'code', min: 1, max: '1' }, { use: 'out', name: 'version', type: 'string', min: 1, max: '1' }, { use: 'out', name: 'lastUpdated', type: 'instant', min: 0, max: '1' }, ], }; /** * Handles HTTP requests for the Agent $status operation. * First reads the agent and makes sure it is valid and the user has access to it. * Then tries to get the agent status from Redis. * Returns the agent status details as a Parameters resource. * * @param req - The FHIR request. * @returns The FHIR response. */ export async function agentStatusHandler(req: FhirRequest): Promise<FhirResponse> { const { repo } = getAuthenticatedContext(); // Read the agent as the user to verify access const agent = await getAgentForRequest(req, repo); if (!agent) { return [badRequest('Must specify agent ID or identifier')]; } const [statusOrOutcome] = await getStatusForAgents([agent]); if (isOperationOutcome(statusOrOutcome)) { return [statusOrOutcome]; } return [allOk, statusOrOutcome]; } /** * Gets the status for a given list of Agents. * @param agents - The agents to get the status of. * @returns A Bundle containing Parameters containing agents with their corresponding status response. */ export async function getStatusForAgents(agents: WithId<Agent>[]): Promise<(Parameters | OperationOutcome)[]> { // Get the agent status details from Redis // This is set by the agent websocket connection // See: packages/server/src/agent/websockets.ts // Here we use MGET to get all the keys at once, which reduces this from O(n) Redis commands to O(1) const statusStrs = await getRedis().mget(agents.map((agent) => `medplum:agent:${agent.id}:info`)); const statuses: (Parameters | OperationOutcome)[] = []; for (let i = 0; i < agents.length; i++) { const statusStr = statusStrs[i]; let output: Parameters | OperationOutcome | undefined; if (statusStr) { const info: AgentInfo = JSON.parse(statusStr); try { output = buildOutputParameters(operation, info); } catch (err) { // If we catch an error here, that means we have an invalid agent info entry output = badRequest(`Invalid agent info: ${normalizeErrorString(err)}`); } } if (output) { statuses.push(output); } else { statuses.push(buildOutputParameters(operation, { status: AgentConnectionState.UNKNOWN, version: 'unknown' })); } } return statuses; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server