Skip to content

Load tiny-agents from Hub #1472

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
13 changes: 11 additions & 2 deletions packages/tiny-agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,19 @@ npx @huggingface/tiny-agents run ./my-agent

Voilà! 🔥


## Tiny Agents collection

Browse our curated collection of Tiny Agents at https://huggingface.co/datasets/tiny-agents/tiny-agents. Each agent is stored in its own subdirectory, following the structure outlined above. Running an agent from the Hub is as simple as using its `agent_id`. For example, to run the [`julien-c/flux-schnell-generator`](https://huggingface.co/datasets/tiny-agents/tiny-agents/tree/main/julien-c/flux-schnell-generator) agent:

```bash
npx @huggingface/tiny-agents run "julien-c/flux-schnell-generator"
```

> [!NOTE]
> Note: you can open a PR in the huggingface.js repo to share your agent with the community, just upload it inside the `src/agents/` directory.
> Want to share your own agent with the community? Submit a PR to the [Tiny Agents](https://huggingface.co/datasets/tiny-agents/tiny-agents/discussions) repository on the Hub. Your submission must include an `agent.json` file, and you can optionally add a `PROMPT.md` file. To help others understand your agent's capabilities, consider including an `EXAMPLES.md` file with sample prompts and use cases.

### Advanced: Programmatic Usage
## Advanced: Programmatic Usage

```typescript
import { Agent } from '@huggingface/tiny-agents';
Expand Down
1 change: 1 addition & 0 deletions packages/tiny-agents/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@huggingface/inference": "workspace:^",
"@huggingface/mcp-client": "workspace:^",
"@huggingface/tasks": "workspace:^",
"@huggingface/hub": "workspace:^",
"@modelcontextprotocol/sdk": "^1.11.4",
"zod": "^3.25.7"
}
Expand Down
3 changes: 3 additions & 0 deletions packages/tiny-agents/pnpm-lock.yaml

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

7 changes: 0 additions & 7 deletions packages/tiny-agents/src/agents/evalstate/hf-search/PROMPT.md

This file was deleted.

12 changes: 0 additions & 12 deletions packages/tiny-agents/src/agents/evalstate/hf-search/agent.json

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

13 changes: 0 additions & 13 deletions packages/tiny-agents/src/agents/julien-c/local-coder/agent.json

This file was deleted.

52 changes: 1 addition & 51 deletions packages/tiny-agents/src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
#!/usr/bin/env node
import { dirname, join } from "node:path";
import { parseArgs } from "node:util";
import { lstat, readFile } from "node:fs/promises";
import { z } from "zod";
import { PROVIDERS_OR_POLICIES } from "@huggingface/inference";
import { Agent } from "@huggingface/mcp-client";
import { version as packageVersion } from "../package.json";
import { ServerConfigSchema } from "./lib/types";
import { debug, error } from "./lib/utils";
import { mainCliLoop } from "./lib/mainCliLoop";
import { loadConfigFrom } from "./lib/loadConfigFrom";

const USAGE_HELP = `
Usage:
Expand All @@ -30,55 +29,6 @@ function isValidCommand(command: string): command is (typeof CLI_COMMANDS)[numbe
return (CLI_COMMANDS as unknown as string[]).includes(command);
}

const FILENAME_CONFIG = "agent.json";
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const FILENAME_PROMPT = "PROMPT.md";

async function loadConfigFrom(loadFrom: string): Promise<{ configJson: string; prompt?: string }> {
try {
/// First try it as a local file path, then as a local directory, then we will try as a path inside the repo itself
return {
configJson: await readFile(loadFrom, { encoding: "utf8" }),
};
} catch {
if ((await lstat(loadFrom)).isDirectory()) {
/// local directory
try {
let prompt: string | undefined;
try {
prompt = await readFile(join(loadFrom, FILENAME_PROMPT), { encoding: "utf8" });
} catch {
debug(`PROMPT.md not found in ${loadFrom}, continuing without prompt template`);
}
return {
configJson: await readFile(join(loadFrom, FILENAME_CONFIG), { encoding: "utf8" }),
prompt,
};
} catch {
error(`Config file not found in specified local directory.`);
process.exit(1);
}
}
const srcDir = dirname(__filename);
const configDir = join(srcDir, "agents", loadFrom);
try {
let prompt: string | undefined;
try {
prompt = await readFile(join(configDir, FILENAME_PROMPT), { encoding: "utf8" });
} catch {
debug(`PROMPT.md not found in ${configDir}, continuing without prompt template`);
}
return {
configJson: await readFile(join(configDir, FILENAME_CONFIG), { encoding: "utf8" }),
prompt,
};
} catch {
error(`Config file not found in tiny-agents repo! Loading from the HF Hub is not implemented yet`);
process.exit(1);
}
}
}

async function main() {
const {
values: { help, version },
Expand Down
105 changes: 105 additions & 0 deletions packages/tiny-agents/src/lib/loadConfigFrom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env node
import { join } from "node:path";
import { lstat, readFile } from "node:fs/promises";
import { downloadFileToCacheDir, type RepoDesignation } from "@huggingface/hub";
import type { TinyAgentConfig } from "./types";
import { debug, error } from "./utils";

const FILENAME_CONFIG = "agent.json";
const FILENAME_PROMPT = "PROMPT.md";

const TINY_AGENTS_HUB_REPO: RepoDesignation = {
name: "tiny-agents/tiny-agents",
type: "dataset",
};

async function tryLoadFromFile(filePath: string): Promise<TinyAgentConfig | undefined> {
try {
const configJson = await readFile(filePath, { encoding: "utf8" });
return { configJson };
} catch {
return undefined;
}
}

async function tryLoadFromDirectory(dirPath: string): Promise<TinyAgentConfig | undefined> {
const stats = await lstat(dirPath).catch(() => undefined);
if (!stats?.isDirectory()) {
return undefined;
}

let prompt: string | undefined;
try {
prompt = await readFile(join(dirPath, FILENAME_PROMPT), { encoding: "utf8" });
} catch {
debug(`PROMPT.md not found in ${dirPath}, continuing without prompt template`);
}

try {
return {
configJson: await readFile(join(dirPath, FILENAME_CONFIG), { encoding: "utf8" }),
prompt,
};
} catch {
error(`Config file not found in specified local directory.`);
process.exit(1);
}
}

async function tryLoadFromHub(agentId: string): Promise<TinyAgentConfig | undefined> {
let configJson: string;
try {
const configPath = await downloadFileToCacheDir({
repo: TINY_AGENTS_HUB_REPO,
path: `${agentId}/${FILENAME_CONFIG}`,
accessToken: process.env.HF_TOKEN,
});
configJson = await readFile(configPath, { encoding: "utf8" });
} catch {
return undefined;
}

let prompt: string | undefined;
try {
const promptPath = await downloadFileToCacheDir({
repo: TINY_AGENTS_HUB_REPO,
path: `${agentId}/${FILENAME_PROMPT}`,
accessToken: process.env.HF_TOKEN,
});
prompt = await readFile(promptPath, { encoding: "utf8" });
} catch {
debug(
`PROMPT.md not found in https://huggingface.co/datasets/tiny-agents/tiny-agents/tree/main/${agentId}, continuing without prompt template`
);
}

return {
configJson,
prompt,
};
}

export async function loadConfigFrom(loadFrom: string): Promise<TinyAgentConfig> {
// First try as a local file
const fileConfig = await tryLoadFromFile(loadFrom);
if (fileConfig) {
return fileConfig;
}

// Then try as a local directory
const dirConfig = await tryLoadFromDirectory(loadFrom);
if (dirConfig) {
return dirConfig;
}

// Finally try loading from repo
const repoConfig = await tryLoadFromHub(loadFrom);
if (repoConfig) {
return repoConfig;
}

error(
`Config file not found in tiny-agents! Please make sure it exists locally or in https://huggingface.co/datasets/tiny-agents/tiny-agents.`
);
process.exit(1);
}
5 changes: 5 additions & 0 deletions packages/tiny-agents/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { z } from "zod";

export interface TinyAgentConfig {
configJson: string;
prompt?: string;
}

export const ServerConfigSchema = z.discriminatedUnion("type", [
z.object({
type: z.literal("stdio"),
Expand Down