Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
22 changes: 22 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@
"@elizaos/plugin-elizacloud": "workspace:*",
"@elizaos/plugin-groq": "workspace:*",
"@elizaos/plugin-local-inference": "workspace:*",
"@elizaos/plugin-nearai": "workspace:*",
"@elizaos/plugin-ollama": "workspace:*",
"@elizaos/plugin-openai": "workspace:*",
"@elizaos/plugin-sql": "workspace:*",
Expand Down
2 changes: 2 additions & 0 deletions packages/agent/src/api/agent-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const PROVIDER_HINTS = [
"ollama",
"mistral",
"together",
"nearai",
"zai",
] as const;

Expand All @@ -50,6 +51,7 @@ const ENV_PROVIDER_SIGNALS: ReadonlyArray<{
{ envVar: "DEEPSEEK_API_KEY", label: "deepseek" },
{ envVar: "MISTRAL_API_KEY", label: "mistral" },
{ envVar: "TOGETHER_API_KEY", label: "together" },
{ envVar: "NEARAI_API_KEY", label: "nearai" },
{ envVar: "ZAI_API_KEY", label: "zai" },
{ envVar: "MOONSHOT_API_KEY", label: "moonshot" },
{ envVar: "OLLAMA_BASE_URL", label: "ollama" },
Expand Down
4 changes: 4 additions & 0 deletions packages/agent/src/api/config-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ const PROVIDER_ENV_KEYS = [
"GROQ_API_KEY",
"XAI_API_KEY",
"OPENROUTER_API_KEY",
"NEARAI_API_KEY",
"NEARAI_BASE_URL",
"NEARAI_SMALL_MODEL",
"NEARAI_LARGE_MODEL",
"AI_GATEWAY_API_KEY",
"AI_GATEWAY_BASE_URL",
"AI_GATEWAY_SMALL_MODEL",
Expand Down
56 changes: 56 additions & 0 deletions packages/agent/src/api/model-provider-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,10 @@ const PROVIDER_ENV_KEYS: Record<
altEnvKeys: ["Z_AI_API_KEY"],
baseUrl: "https://api.z.ai/api/paas/v4",
},
nearai: {
envKey: "NEARAI_API_KEY",
baseUrl: "https://cloud-api.near.ai/v1",
},
moonshot: {
envKey: "MOONSHOT_API_KEY",
altEnvKeys: ["KIMI_API_KEY"],
Expand Down Expand Up @@ -529,6 +533,49 @@ export async function fetchVercelGatewayModels(
}
}

/** Fetch NEAR AI Cloud models from its public catalog endpoint. */
export async function fetchNearAIModels(
apiKey: string,
baseUrl: string,
): Promise<CachedModel[]> {
try {
const url = `${baseUrl.replace(/\/+$/, "")}/model/list`;
const headers: Record<string, string> = {};
if (apiKey) headers.Authorization = `Bearer ${apiKey}`;
const res = await fetch(url, { headers });
if (!res.ok) return [];
const data = (await res.json()) as {
models?: Array<{
modelId: string;
metadata?: {
modelDisplayName?: string;
architecture?: { outputModalities?: string[] };
};
}>;
};
return (data.models ?? [])
.map((model) => {
const outputs = model.metadata?.architecture?.outputModalities ?? [];
const category = outputs.some(
(output) => output.toLowerCase() === "image",
)
? "image"
: classifyModel(model.modelId);
return {
id: model.modelId,
name: model.metadata?.modelDisplayName ?? model.modelId,
category,
};
})
.sort((a, b) => a.id.localeCompare(b.id));
} catch (e: unknown) {
logger.warn(
`[model-catalog] Failed to fetch NEAR AI models: ${e instanceof Error ? e.message : e}`,
);
return [];
}
}

export async function fetchProviderModels(
providerId: string,
apiKey: string,
Expand Down Expand Up @@ -573,6 +620,11 @@ export async function fetchProviderModels(
apiKey,
baseUrl ?? "https://api.z.ai/api/paas/v4",
);
case "nearai":
return fetchNearAIModels(
apiKey,
baseUrl ?? "https://cloud-api.near.ai/v1",
);
case "moonshot":
return fetchModelsREST(
providerId,
Expand Down Expand Up @@ -614,12 +666,16 @@ export async function getOrFetchProvider(
baseUrl =
process.env.AI_GATEWAY_BASE_URL?.trim() ||
"https://ai-gateway.vercel.sh/v1";
} else if (providerId === "nearai") {
baseUrl =
process.env.NEARAI_BASE_URL?.trim() || "https://cloud-api.near.ai/v1";
}

// Skip remote providers that need an API key when none is configured
const keylessProviders = new Set([
"ollama",
"openrouter",
"nearai",
"vercel-ai-gateway",
]);
if (!keyValue && !keylessProviders.has(providerId)) return [];
Comment thread
greptile-apps[bot] marked this conversation as resolved.
Expand Down
1 change: 1 addition & 0 deletions packages/agent/src/api/plugin-discovery-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,7 @@ export function categorizePlugin(
"perplexity",
"minimax",
"zai",
"nearai",
];
const connectors = [
"telegram",
Expand Down
7 changes: 7 additions & 0 deletions packages/agent/src/api/provider-switch-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,12 @@ const PROVIDER_DEFAULT_MODELS: Record<
largeKey: "GROQ_LARGE_MODEL",
largeVal: "openai/gpt-oss-120b",
},
nearai: {
smallKey: "NEARAI_SMALL_MODEL",
smallVal: "Qwen/Qwen3.6-35B-A3B-FP8",
largeKey: "NEARAI_LARGE_MODEL",
largeVal: "zai-org/GLM-5.1-FP8",
},
// MLX (Apple Silicon, mlx_lm.server). Defaults pick small/fast 4-bit
// quantizations from the `mlx-community` HuggingFace org — they're the
// canonical converted models the MLX team publishes. Operators with their
Expand Down Expand Up @@ -713,6 +719,7 @@ export function clearPersistedOnboardingConfig(
"mistral",
"mlx",
"moonshot",
"nearai",
"ollama",
"openai",
"openai-subscription",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { afterEach, describe, expect, it } from "vitest";
import type { ElizaConfig } from "../../config/config";
import { collectPluginNames } from "../plugin-collector";

const originalEnv = { ...process.env };

afterEach(() => {
process.env = { ...originalEnv };
});

function minimalConfig(): ElizaConfig {
return {} as ElizaConfig;
}

describe("NEAR AI plugin collection", () => {
it("loads the first-party NEAR AI plugin from NEARAI_API_KEY", () => {
process.env.NEARAI_API_KEY = "test-key";

const plugins = collectPluginNames(minimalConfig());

expect(plugins.has("@elizaos/plugin-nearai")).toBe(true);
});
});
7 changes: 7 additions & 0 deletions packages/agent/src/runtime/first-time-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,13 @@ export async function runFirstTimeSetup(
detectKeys: ["ZAI_API_KEY", "Z_AI_API_KEY"],
hint: "",
},
{
id: "nearai",
label: "NEAR AI",
envKey: "NEARAI_API_KEY",
detectKeys: ["NEARAI_API_KEY"],
hint: "",
},
{
id: "moonshot",
label: "Kimi / Moonshot",
Expand Down
1 change: 1 addition & 0 deletions packages/agent/src/runtime/plugin-collector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export const PROVIDER_PLUGIN_MAP: Readonly<Record<string, string>> = {
AIGATEWAY_API_KEY: "@elizaos/plugin-vercel-ai-gateway",
OLLAMA_BASE_URL: "@elizaos/plugin-ollama",
MLX_BASE_URL: "@elizaos/plugin-mlx",
NEARAI_API_KEY: "@elizaos/plugin-nearai",
ZAI_API_KEY: "@elizaos/plugin-zai",
Z_AI_API_KEY: "@elizaos/plugin-zai",
// ElizaCloud — loaded when API key is present OR cloud is explicitly enabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ const ENV_PROVIDER_MAP: Array<{
providerId: "together",
authMode: "api-key",
},
{ envVar: "NEARAI_API_KEY", providerId: "nearai", authMode: "api-key" },
{ envVar: "ZAI_API_KEY", providerId: "zai", authMode: "api-key" },
{
envVar: "OLLAMA_BASE_URL",
Expand Down Expand Up @@ -734,6 +735,10 @@ const VALIDATION_ENDPOINTS: Record<
url: "https://api.z.ai/api/paas/v4/models",
authHeader: (key) => ({ Authorization: `Bearer ${key}` }),
},
nearai: {
url: "https://cloud-api.near.ai/v1/model/list",
authHeader: (key) => ({ Authorization: `Bearer ${key}` }),
},
};

async function validateProvider(
Expand Down
1 change: 1 addition & 0 deletions packages/app-core/scripts/generate-plugin-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const AI_PROVIDERS = new Set([
"perplexity",
"minimax",
"zai",
"nearai",
]);

export const STREAMING_DESTINATIONS = new Set(["streaming"]);
Expand Down
6 changes: 6 additions & 0 deletions packages/app-core/src/api/credential-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ const CREDENTIAL_SOURCES: CredentialSource[] = [
process.env.Z_AI_API_KEY?.trim() ||
null,
},
{
providerId: "nearai",
envVar: "NEARAI_API_KEY",
authType: "api-key",
resolve: () => process.env.NEARAI_API_KEY?.trim() || null,
},
{
providerId: "moonshot",
envVar: "MOONSHOT_API_KEY",
Expand Down
73 changes: 73 additions & 0 deletions packages/app-core/src/registry/entries/plugins/nearai.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{
"id": "nearai",
"name": "NEAR AI",
"description": "NEAR AI Cloud TEE inference provider via an OpenAI-compatible API.",
"npmName": "@elizaos/plugin-nearai",
"version": "2.0.0-beta.0",
"source": "bundled",
"tags": ["ai-provider", "llm", "nearai", "near-ai", "tee", "chat"],
"config": {
"NEARAI_API_KEY": {
"type": "secret",
"required": true,
"sensitive": true,
"label": "API Key",
"help": "API key used to authenticate requests to NEAR AI Cloud.",
"advanced": false
},
"NEARAI_BASE_URL": {
"type": "url",
"required": false,
"sensitive": false,
"default": "https://cloud-api.near.ai/v1",
"label": "Base URL",
"help": "Base URL for the NEAR AI Cloud OpenAI-compatible API.",
"advanced": false
},
"NEARAI_SMALL_MODEL": {
"type": "string",
"required": false,
"sensitive": false,
"default": "Qwen/Qwen3.6-35B-A3B-FP8",
"label": "Small Model",
"help": "Override the default NEAR AI small text model identifier.",
"placeholder": "e.g., Qwen/Qwen3.6-35B-A3B-FP8",
"advanced": false
},
"NEARAI_LARGE_MODEL": {
"type": "string",
"required": false,
"sensitive": false,
"default": "zai-org/GLM-5.1-FP8",
"label": "Large Model",
"help": "Override the default NEAR AI large text model identifier.",
"placeholder": "e.g., zai-org/GLM-5.1-FP8",
"advanced": false
},
"NEARAI_BROWSER_BASE_URL": {
"type": "url",
"required": false,
"sensitive": false,
"label": "Browser Base URL",
"help": "Browser-only proxy endpoint base URL for NEAR AI requests. Do not expose API keys in browser clients.",
"advanced": true
}
},
"render": {
"visible": true,
"pinTo": [],
"style": "card",
"icon": "ShieldCheck",
"group": "ai-provider",
"groupOrder": 0,
"actions": ["enable", "configure"]
},
"resources": {
"homepage": "https://near.ai",
"repository": "https://github.com/elizaos-plugins/plugin-nearai",
"setupGuideUrl": "https://docs.eliza.ai/plugin-setup-guide#near-ai"
},
"dependsOn": [],
"kind": "plugin",
"subtype": "ai-provider"
}
Loading
Loading