Skip to content

Create a tiny-agents package #1451

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

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ const agent = new Agent({
],
});


await agent.loadTools();

for await (const chunk of agent.run("What are the top 5 trending models on Hugging Face?")) {
if ("choices" in chunk) {
const delta = chunk.choices[0]?.delta;
Expand Down
1 change: 1 addition & 0 deletions packages/mcp-client/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./McpClient";
export * from "./Agent";
export type { ChatCompletionInputMessageTool } from "./McpClient";
export type { ServerConfig } from "./types";
71 changes: 71 additions & 0 deletions packages/tiny-agents/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# @huggingface/tiny-agents

A lightweight, composable agent framework for AI applications built on Hugging Face's JS stack.

## Installation

```bash
npm install @huggingface/tiny-agents
# or
yarn add @huggingface/tiny-agents
# or
pnpm add @huggingface/tiny-agents
```

## CLI Usage

```bash
npx @huggingface/tiny-agents [command] "agent/id"

```

```
Usage:
tiny-agents [flags]
tiny-agents run "agent/id"
tiny-agents serve "agent/id"

Available Commands:
run Run the Agent in command-line
serve Run the Agent as an OpenAI-compatible HTTP server
Copy link
Collaborator

@evalstate evalstate May 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

being able to run OR serve from the same config is 👌

```


## Programmatic Usage

```typescript
import { Agent } from '@huggingface/tiny-agents';

const HF_TOKEN = "hf_...";

// Create an Agent
const agent = new Agent({
provider: "auto",
model: "Qwen/Qwen2.5-72B-Instruct",
apiKey: HF_TOKEN,
servers: [
{
// Playwright MCP
command: "npx",
args: ["@playwright/mcp@latest"],
},
],
});

await agent.loadTools();

// Use the Agent
for await (const chunk of agent.run("What are the top 5 trending models on Hugging Face?")) {
if ("choices" in chunk) {
const delta = chunk.choices[0]?.delta;
if (delta.content) {
console.log(delta.content);
}
}
}
```


## License

MIT
58 changes: 58 additions & 0 deletions packages/tiny-agents/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "@huggingface/tiny-agents",
"packageManager": "[email protected]",
"version": "0.1.0",
"description": "Lightweight, composable agents for AI applications",
"repository": "https://github.com/huggingface/huggingface.js.git",
"publishConfig": {
"access": "public"
},
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"bin": {
"tiny-agents": "./dist/cli.js"
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"require": "./dist/index.js",
"import": "./dist/index.mjs"
}
},
"engines": {
"node": ">=18"
},
"source": "index.ts",
"scripts": {
"lint": "eslint --quiet --fix --ext .cjs,.ts .",
"lint:check": "eslint --ext .cjs,.ts .",
"format": "prettier --write .",
"format:check": "prettier --check .",
"prepublishOnly": "pnpm run build",
"build": "tsup src/index.ts --format cjs,esm --clean && tsc --emitDeclarationOnly --declaration",
"prepare": "pnpm run build",
"test": "vitest run",
"check": "tsc",
"cli": "tsx src/cli.ts"
},
"files": [
"src",
"dist",
"tsconfig.json"
],
"keywords": [
"huggingface",
"agent",
"ai",
"llm",
"tiny-agent"
],
"author": "Hugging Face",
"license": "MIT",
"dependencies": {
"@huggingface/inference": "workspace:^",
"@huggingface/mcp-client": "workspace:^",
"zod": "^3.24.4"
}
}
28 changes: 28 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.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"model": "Qwen/Qwen3-32B",
"provider": "novita",
"servers": [
{
"type": "sse",
"config": {
"url": "https://evalstate-flux1-schnell.hf.space/gradio_api/mcp/sse"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
You are an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user. Only terminate your turn when you are sure that the problem is solved, or if you need more info from the user to solve the problem.

If you are not sure about anything pertaining to the user’s request, use your tools to read files and gather the relevant information: do NOT guess or make up an answer.

You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.
13 changes: 13 additions & 0 deletions packages/tiny-agents/src/agents/julien-c/local-coder/agent.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
Copy link
Collaborator

@evalstate evalstate May 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://gitmcp.io/ <-- for demo this is a nice remote server for a coding agent. (it makes any github repo an MCP server!). (just announced it now supports streaming http!)

"model": "Qwen/Qwen2.5-72B-Instruct",
"provider": "nebius",
"servers": [
{
"type": "stdio",
"config": {
"command": "npx",
"args": ["@playwright/mcp@latest"]
}
}
]
}
117 changes: 117 additions & 0 deletions packages/tiny-agents/src/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#!/usr/bin/env node
import { dirname, join } from "node:path";
import { parseArgs } from "node:util";
import { readFile } from "node:fs/promises";
import { z } from "zod";
import { PROVIDERS_OR_POLICIES } from "@huggingface/inference";
import { Agent } from "@huggingface/mcp-client";
import type { ServerConfig } from "@huggingface/mcp-client";
import { version as packageVersion } from "../package.json";

const USAGE_HELP = `
Usage:
tiny-agents [flags]
tiny-agents run "agent/id"
tiny-agents serve "agent/id"

Available Commands:
run Run the Agent in command-line
serve Run the Agent as an OpenAI-compatible HTTP server

Flags:
-h, --help help for tiny-agents
-v, --version Show version information
`.trim();

const CLI_COMMANDS = ["run", "serve"] as const;
function isValidCommand(command: string): command is (typeof CLI_COMMANDS)[number] {
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<string> {
try {
/// First try it as a local directory path, then we will try as a path inside the repo itself
return await readFile(loadFrom, { encoding: "utf8" });
} catch {
const srcDir = dirname(__filename);
const configPath = join(srcDir, "agents", loadFrom, FILENAME_CONFIG);
try {
return await readFile(configPath, { encoding: "utf8" });
} catch {
console.error(`Config file not found! Loading from the HF Hub is not implemented yet`);
process.exit(1);
}
}
}

async function main() {
const {
values: { help, version },
positionals,
} = parseArgs({
options: {
help: {
type: "boolean",
short: "h",
},
version: {
type: "boolean",
short: "v",
},
},
allowPositionals: true,
});
if (version) {
console.log(packageVersion);
process.exit(0);
}
const command = positionals[0];
const loadFrom = positionals[1];
if (help) {
console.log(USAGE_HELP);
process.exit(0);
}
if (positionals.length !== 2 || !isValidCommand(command)) {
console.error(`You need to call run or serve, followed by an agent id (local path or Hub identifier).`);
console.log(USAGE_HELP);
process.exit(1);
}

if (command === "serve") {
console.error(`Serve is not implemented yet, coming soon!`);
process.exit(1);
} else {
const configJson = await loadConfigFrom(loadFrom);

const ConfigSchema = z.object({
model: z.string(),
provider: z.enum(PROVIDERS_OR_POLICIES),
servers: z.array(z.custom<ServerConfig>()),
});

let config: z.infer<typeof ConfigSchema>;
try {
const parsedConfig = JSON.parse(configJson);
config = ConfigSchema.parse(parsedConfig);
} catch (error) {
console.error("Invalid configuration file:", error instanceof Error ? error.message : error);
process.exit(1);
}
const agent = new Agent({
provider: config.provider,
model: config.model,
apiKey: process.env.HF_TOKEN ?? "",
servers: config.servers,
});

console.log(agent);

// TODO: hook main loop from mcp-client/cli.ts
}
}

main();
1 change: 1 addition & 0 deletions packages/tiny-agents/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably some code should be added for programmatic usage?

21 changes: 21 additions & 0 deletions packages/tiny-agents/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"lib": ["ES2022", "DOM"],
"module": "CommonJS",
"moduleResolution": "node",
"target": "ES2022",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"skipLibCheck": true,
"noImplicitOverride": true,
"outDir": "./dist",
"declaration": true,
"declarationMap": true,
"resolveJsonModule": true
},
"include": ["src", "test"],
"exclude": ["dist"]
}