Skip to content

Commit 40c84bd

Browse files
authored
Merge branch 'main' into provider-featherless-ai
2 parents 762207a + ba6e1a8 commit 40c84bd

39 files changed

+7494
-7742
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</p>
1111

1212
```ts
13-
// Programatically interact with the Hub
13+
// Programmatically interact with the Hub
1414

1515
await createRepo({
1616
repo: { type: "model", name: "my-user/nlp-model" },
@@ -97,8 +97,8 @@ You can run our packages with vanilla JS, without any bundler, by using a CDN or
9797

9898
```html
9999
<script type="module">
100-
import { InferenceClient } from 'https://cdn.jsdelivr.net/npm/@huggingface/[email protected].1/+esm';
101-
import { createRepo, commit, deleteRepo, listFiles } from "https://cdn.jsdelivr.net/npm/@huggingface/[email protected].1/+esm";
100+
import { InferenceClient } from 'https://cdn.jsdelivr.net/npm/@huggingface/[email protected].2/+esm';
101+
import { createRepo, commit, deleteRepo, listFiles } from "https://cdn.jsdelivr.net/npm/@huggingface/[email protected].2/+esm";
102102
</script>
103103
```
104104

packages/agents/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const agent = new HfAgent(
5858

5959

6060
#### From your own endpoints
61-
You can also specify your own endpoint, as long as it implements the same API, for exemple using [text generation inference](https://github.com/huggingface/text-generation-inference) and [Inference Endpoints](https://huggingface.co/inference-endpoints).
61+
You can also specify your own endpoint, as long as it implements the same API, for example using [text generation inference](https://github.com/huggingface/text-generation-inference) and [Inference Endpoints](https://huggingface.co/inference-endpoints).
6262

6363
```ts
6464
import { HfAgent, LLMFromEndpoint } from "@huggingface/agents";

packages/hub/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@huggingface/hub",
33
"packageManager": "[email protected]",
4-
"version": "1.1.1",
4+
"version": "1.1.2",
55
"description": "Utilities to interact with the Hugging Face hub",
66
"repository": "https://github.com/huggingface/huggingface.js.git",
77
"publishConfig": {

packages/hub/src/lib/download-file-to-cache-dir.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,6 @@ describe("downloadFileToCacheDir", () => {
288288
// 2. should rename the incomplete to the blob expected name
289289
expect(rename).toHaveBeenCalledWith(incomplete, expectedBlob);
290290
// 3. should create symlink pointing to blob
291-
expect(createSymlink).toHaveBeenCalledWith(expectedBlob, expectPointer);
291+
expect(createSymlink).toHaveBeenCalledWith({ sourcePath: expectedBlob, finalPath: expectPointer });
292292
});
293293
});

packages/hub/src/lib/download-file-to-cache-dir.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export async function downloadFileToCacheDir(
108108
// shortcut the download if needed
109109
if (await exists(blobPath)) {
110110
// create symlinks in snapshot folder to blob object
111-
await createSymlink(blobPath, pointerPath);
111+
await createSymlink({ sourcePath: blobPath, finalPath: pointerPath });
112112
return pointerPath;
113113
}
114114

@@ -128,6 +128,6 @@ export async function downloadFileToCacheDir(
128128
// rename .incomplete file to expect blob
129129
await rename(incomplete, blobPath);
130130
// create symlinks in snapshot folder to blob object
131-
await createSymlink(blobPath, pointerPath);
131+
await createSymlink({ sourcePath: blobPath, finalPath: pointerPath });
132132
return pointerPath;
133133
}

packages/hub/src/lib/oauth-login-url.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,12 @@ export async function oauthLoginUrl(opts?: {
109109
if (opts?.localStorage) {
110110
if (opts.localStorage.codeVerifier !== undefined && opts.localStorage.codeVerifier !== null) {
111111
throw new Error(
112-
"localStorage.codeVerifier must be a initially set to null or undefined, and will be filled by oauthLoginUrl"
112+
"localStorage.codeVerifier must be initially set to null or undefined, and will be filled by oauthLoginUrl"
113113
);
114114
}
115115
if (opts.localStorage.nonce !== undefined && opts.localStorage.nonce !== null) {
116116
throw new Error(
117-
"localStorage.nonce must be a initially set to null or undefined, and will be filled by oauthLoginUrl"
117+
"localStorage.nonce must be initially set to null or undefined, and will be filled by oauthLoginUrl"
118118
);
119119
}
120120
opts.localStorage.codeVerifier = newCodeVerifier;

packages/hub/src/types/api/api-model.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ Also encode config params into the name if relevant.
117117
[x: string]: string;
118118
};
119119
/**
120-
* [Automatically computed, do not set] Dynamically overriden by huggingface in API calls to indicate if it was verified by Hugging Face.
120+
* [Automatically computed, do not set] Dynamically overridden by huggingface in API calls to indicate if it was verified by Hugging Face.
121121
*/
122122
verified?: boolean;
123123
/**

packages/hub/src/utils/XetBlob.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ describe("XetBlob", () => {
9898
}
9999
return fetch(url, opts);
100100
},
101-
internalLogging: true,
101+
// internalLogging: true,
102102
});
103103

104104
const xetDownload = await blob.slice(0, 200_000).arrayBuffer();
@@ -124,7 +124,7 @@ describe("XetBlob", () => {
124124
},
125125
hash: "7b3b6d07673a88cf467e67c1f7edef1a8c268cbf66e9dd9b0366322d4ab56d9b",
126126
size: 5_234_139_343,
127-
internalLogging: true,
127+
// internalLogging: true,
128128
});
129129

130130
const xetDownload = await blob.slice(10_000_000, 10_100_000).arrayBuffer();
+72-46
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,89 @@
1-
import { describe, test, expect, vi, beforeEach } from "vitest";
2-
import * as fs from "node:fs/promises";
1+
/* eslint-disable @typescript-eslint/consistent-type-imports */
2+
/* eslint-disable @typescript-eslint/no-explicit-any */
3+
import { describe, expect, it, vi } from "vitest";
34
import { createSymlink } from "./symlink";
4-
import * as path from "node:path";
5-
import type { FileHandle } from "node:fs/promises";
6-
7-
vi.mock("node:fs/promises", () => ({
8-
rm: vi.fn(),
9-
symlink: vi.fn(),
10-
rename: vi.fn(),
11-
copyFile: vi.fn(),
12-
mkdir: vi.fn(),
13-
mkdtemp: vi.fn(),
14-
open: vi.fn(),
15-
}));
5+
import { readFileSync, writeFileSync } from "node:fs";
6+
import { lstat, rm } from "node:fs/promises";
7+
import { tmpdir } from "node:os";
8+
import { join } from "node:path";
9+
10+
let failSymlink = false;
11+
vi.mock("node:fs/promises", async (importOriginal) => ({
12+
...(await importOriginal<typeof import("node:fs/promises")>()),
13+
symlink: async (...args: any[]) => {
14+
if (failSymlink) {
15+
failSymlink = false;
16+
throw new Error("Symlink not supported");
17+
}
1618

17-
vi.mock("node:os", () => ({
18-
platform: vi.fn(),
19+
// @ts-expect-error - ignore
20+
return (await importOriginal<typeof import("node:fs/promises")>()).symlink(...args);
21+
},
1922
}));
2023

21-
describe("createSymlink", () => {
22-
const src = "/path/to/src";
23-
const dst = "/path/to/dst";
24+
describe("utils/symlink", () => {
25+
it("should create a symlink", async () => {
26+
writeFileSync(join(tmpdir(), "test.txt"), "hello world");
27+
await createSymlink({
28+
sourcePath: join(tmpdir(), "test.txt"),
29+
finalPath: join(tmpdir(), "test-symlink.txt"),
30+
});
2431

25-
beforeEach(() => {
26-
vi.resetAllMocks();
27-
vi.mocked(fs.mkdtemp).mockImplementation(async (prefix) => `${prefix}/temp`);
28-
vi.mocked(fs.open).mockResolvedValue({ close: vi.fn() } as unknown as FileHandle);
29-
});
32+
const stats = await lstat(join(tmpdir(), "test-symlink.txt"));
33+
expect(stats.isSymbolicLink()).toBe(process.platform !== "win32");
3034

31-
test("should remove existing destination", async () => {
32-
await createSymlink(dst, src);
33-
expect(fs.rm).toHaveBeenCalledWith(dst);
35+
// Test file content
36+
const content = readFileSync(join(tmpdir(), "test-symlink.txt"), "utf8");
37+
expect(content).toBe("hello world");
38+
39+
// Cleanup
40+
await rm(join(tmpdir(), "test-symlink.txt"));
41+
await rm(join(tmpdir(), "test.txt"));
3442
});
3543

36-
describe("symlink not supported (Windows)", () => {
37-
beforeEach(() => {
38-
vi.mocked(fs.symlink).mockRejectedValue(new Error("Symlink not supported"));
44+
it("should work when symlinking twice", async () => {
45+
writeFileSync(join(tmpdir(), "test.txt"), "hello world");
46+
writeFileSync(join(tmpdir(), "test2.txt"), "hello world2");
47+
await createSymlink({
48+
sourcePath: join(tmpdir(), "test.txt"),
49+
finalPath: join(tmpdir(), "test-symlink.txt"),
3950
});
40-
41-
test("should copyfile", async () => {
42-
await createSymlink(dst, src);
43-
expect(fs.copyFile).toHaveBeenCalledWith(path.resolve(dst), path.resolve(src));
51+
await createSymlink({
52+
sourcePath: join(tmpdir(), "test2.txt"),
53+
finalPath: join(tmpdir(), "test-symlink.txt"),
4454
});
4555

46-
test("should rename file if new_blob is true", async () => {
47-
await createSymlink(dst, src, true);
48-
expect(fs.rename).toHaveBeenCalledWith(path.resolve(dst), path.resolve(src));
49-
});
56+
const stats = await lstat(join(tmpdir(), "test-symlink.txt"));
57+
expect(stats.isSymbolicLink()).toBe(process.platform !== "win32");
58+
59+
// Test file content
60+
const content = readFileSync(join(tmpdir(), "test-symlink.txt"), "utf8");
61+
expect(content).toBe("hello world2");
62+
63+
// Cleanup
64+
await rm(join(tmpdir(), "test-symlink.txt"));
65+
await rm(join(tmpdir(), "test.txt"));
66+
await rm(join(tmpdir(), "test2.txt"));
5067
});
5168

52-
describe("symlink supported", () => {
53-
test("should symlink", async () => {
54-
await createSymlink(dst, src);
55-
expect(fs.symlink).toHaveBeenCalledWith(path.resolve(dst), path.resolve(src));
56-
});
69+
it("should work when symlink doesn't work (windows)", async () => {
70+
writeFileSync(join(tmpdir(), "test.txt"), "hello world");
5771

58-
test("should symlink if new_blob is true", async () => {
59-
await createSymlink(dst, src, true);
60-
expect(fs.symlink).toHaveBeenCalledWith(path.resolve(dst), path.resolve(src));
72+
failSymlink = true;
73+
await createSymlink({
74+
sourcePath: join(tmpdir(), "test.txt"),
75+
finalPath: join(tmpdir(), "test-symlink.txt"),
6176
});
77+
78+
const stats = await lstat(join(tmpdir(), "test-symlink.txt"));
79+
expect(stats.isSymbolicLink()).toBe(false);
80+
81+
// Test file content
82+
const content = readFileSync(join(tmpdir(), "test-symlink.txt"), "utf8");
83+
expect(content).toBe("hello world");
84+
85+
// Cleanup
86+
await rm(join(tmpdir(), "test-symlink.txt"));
87+
await rm(join(tmpdir(), "test.txt"));
6288
});
6389
});

packages/hub/src/utils/symlink.ts

+20-18
Original file line numberDiff line numberDiff line change
@@ -36,28 +36,30 @@ function expandUser(path: string): string {
3636
* having the actual file in `dst`. If it is a new file (`new_blob=True`), we move it to `dst`. If it is not a new file
3737
* (`new_blob=False`), we don't know if the blob file is already referenced elsewhere. To avoid breaking existing
3838
* cache, the file is duplicated on the disk.
39-
*
40-
* In case symlinks are not supported, a warning message is displayed to the user once when loading `huggingface_hub`.
41-
* The warning message can be disabled with the `HF_HUB_DISABLE_SYMLINKS_WARNING` environment variable.
4239
*/
43-
export async function createSymlink(dst: string, src: string, new_blob?: boolean): Promise<void> {
40+
export async function createSymlink(params: {
41+
/**
42+
* The path to the symlink.
43+
*/
44+
finalPath: string;
45+
/**
46+
* The path the symlink should point to.
47+
*/
48+
sourcePath: string;
49+
}): Promise<void> {
50+
const abs_src = path.resolve(expandUser(params.sourcePath));
51+
const abs_dst = path.resolve(expandUser(params.finalPath));
52+
4453
try {
45-
await fs.rm(dst);
46-
} catch (_e: unknown) {
47-
/* empty */
54+
await fs.rm(abs_dst);
55+
} catch {
56+
// ignore
4857
}
49-
const abs_src = path.resolve(expandUser(src));
50-
const abs_dst = path.resolve(expandUser(dst));
5158

5259
try {
53-
await fs.symlink(abs_dst, abs_src);
54-
} catch (_e: unknown) {
55-
if (new_blob) {
56-
console.info(`Symlink not supported. Moving file from ${abs_src} to ${abs_dst}`);
57-
await fs.rename(abs_dst, abs_src);
58-
} else {
59-
console.info(`Symlink not supported. Copying file from ${abs_src} to ${abs_dst}`);
60-
await fs.copyFile(abs_dst, abs_src);
61-
}
60+
await fs.symlink(path.relative(path.dirname(abs_dst), abs_src), abs_dst);
61+
} catch {
62+
console.info(`Symlink not supported. Copying file from ${abs_src} to ${abs_dst}`);
63+
await fs.copyFile(abs_src, abs_dst);
6264
}
6365
}

packages/hub/vitest.config.mts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import { defineConfig } from "vitest/config";
22

33
export default defineConfig({
44
test: {
5-
testTimeout: 30_000,
5+
testTimeout: 60_000,
66
},
77
});

packages/inference/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@huggingface/inference",
3-
"version": "3.6.1",
3+
"version": "3.6.2",
44
"packageManager": "[email protected]",
55
"license": "MIT",
66
"author": "Hugging Face and Tim Mikeladze <[email protected]>",

packages/inference/src/lib/makeRequestOptions.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,11 @@ export function makeRequestOptionsFromResolvedModel(
145145
? endpointUrl + `/v1/chat/completions`
146146
: endpointUrl
147147
: providerConfig.makeUrl({
148+
authMethod,
148149
baseUrl:
149150
authMethod !== "provider-key"
150151
? HF_HUB_INFERENCE_PROXY_TEMPLATE.replace("{{PROVIDER}}", provider)
151-
: providerConfig.baseUrl,
152+
: providerConfig.makeBaseUrl(task),
152153
model: resolvedModel,
153154
chatCompletion,
154155
task,

packages/inference/src/providers/black-forest-labs.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414
*
1515
* Thanks!
1616
*/
17-
import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types";
17+
import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types";
1818

1919
const BLACK_FOREST_LABS_AI_API_BASE_URL = "https://api.us1.bfl.ai";
2020

21+
const makeBaseUrl = (): string => {
22+
return BLACK_FOREST_LABS_AI_API_BASE_URL;
23+
};
24+
2125
const makeBody = (params: BodyParams): Record<string, unknown> => {
2226
return params.args;
2327
};
@@ -35,7 +39,7 @@ const makeUrl = (params: UrlParams): string => {
3539
};
3640

3741
export const BLACK_FOREST_LABS_CONFIG: ProviderConfig = {
38-
baseUrl: BLACK_FOREST_LABS_AI_API_BASE_URL,
42+
makeBaseUrl,
3943
makeBody,
4044
makeHeaders,
4145
makeUrl,

packages/inference/src/providers/cerebras.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414
*
1515
* Thanks!
1616
*/
17-
import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types";
17+
import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types";
1818

1919
const CEREBRAS_API_BASE_URL = "https://api.cerebras.ai";
2020

21+
const makeBaseUrl = (): string => {
22+
return CEREBRAS_API_BASE_URL;
23+
};
24+
2125
const makeBody = (params: BodyParams): Record<string, unknown> => {
2226
return {
2327
...params.args,
@@ -34,7 +38,7 @@ const makeUrl = (params: UrlParams): string => {
3438
};
3539

3640
export const CEREBRAS_CONFIG: ProviderConfig = {
37-
baseUrl: CEREBRAS_API_BASE_URL,
41+
makeBaseUrl,
3842
makeBody,
3943
makeHeaders,
4044
makeUrl,

packages/inference/src/providers/cohere.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414
*
1515
* Thanks!
1616
*/
17-
import type { ProviderConfig, UrlParams, HeaderParams, BodyParams } from "../types";
17+
import type { BodyParams, HeaderParams, ProviderConfig, UrlParams } from "../types";
1818

1919
const COHERE_API_BASE_URL = "https://api.cohere.com";
2020

21+
const makeBaseUrl = (): string => {
22+
return COHERE_API_BASE_URL;
23+
};
24+
2125
const makeBody = (params: BodyParams): Record<string, unknown> => {
2226
return {
2327
...params.args,
@@ -34,7 +38,7 @@ const makeUrl = (params: UrlParams): string => {
3438
};
3539

3640
export const COHERE_CONFIG: ProviderConfig = {
37-
baseUrl: COHERE_API_BASE_URL,
41+
makeBaseUrl,
3842
makeBody,
3943
makeHeaders,
4044
makeUrl,

0 commit comments

Comments
 (0)