-
Notifications
You must be signed in to change notification settings - Fork 381
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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"; |
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 | ||
``` | ||
|
||
|
||
## 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 |
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" | ||
} | ||
} |
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. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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"] | ||
} | ||
} | ||
] | ||
} |
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(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably some code should be added for programmatic usage? |
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"] | ||
} |
There was a problem hiding this comment.
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 👌