Skip to content
Merged
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: 0 additions & 2 deletions bunfig.toml

This file was deleted.

63 changes: 63 additions & 0 deletions e2e/live.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Live calls against xAI's CLI chat proxy. Opt in by setting
// XAI_LIVE_ACCESS_TOKEN (a grok CLI OAuth access token). XAI_LIVE_MODEL is
// optional and must be one of XAI_DEFAULT_MODELS.

import { describe, expect, test } from "bun:test";
import { createDependencies, runInference } from "@intx/inference";
import type { InferenceEvent, InferenceSource } from "@intx/types/runtime";
import {
createXaiResponsesAdapter,
XAI_DEFAULT_MODELS,
XAI_OAUTH_PROXY_BASE_URL,
XAI_PROVIDER,
XAI_USER_ID_OPTION,
xaiUserIdFromAccessToken,
} from "../src/index";

const accessToken = process.env["XAI_LIVE_ACCESS_TOKEN"] ?? "";
const model = process.env["XAI_LIVE_MODEL"] ?? XAI_DEFAULT_MODELS[0];

const source: InferenceSource = {
id: `xai:${model}`,
provider: XAI_PROVIDER,
baseURL: XAI_OAUTH_PROXY_BASE_URL,
credentialId: "xai",
model,
};

const deps = createDependencies({
has: (provider) => provider === XAI_PROVIDER,
resolve: createXaiResponsesAdapter,
});

describe.skipIf(accessToken === "")("live xAI CLI chat proxy", () => {
test("streams a text turn", async () => {
const userId = xaiUserIdFromAccessToken(accessToken);
if (userId === undefined)
throw new Error("XAI_LIVE_ACCESS_TOKEN is not a JWT with a sub claim");
let seq = 0;
const events: InferenceEvent[] = [];
for await (const ev of runInference({
turns: [
{
role: "user",
timestamp: 0,
content: [{ type: "text", text: "Reply with the word pong." }],
},
],
source,
inferenceOptions: {
providerOptions: { [XAI_USER_ID_OPTION]: userId },
},
nextSeq: () => seq++,
readMaterial: () => ({ secret: accessToken }),
deps,
}))
events.push(ev);
const done = events.find((e) => e.type === "inference.done");
if (done?.type !== "inference.done")
throw new Error(`expected inference.done, got ${JSON.stringify(events)}`);
const text = done.data.turn.content.find((b) => b.type === "text");
expect(text?.type === "text" && text.text.toLowerCase()).toContain("pong");
}, 60_000);
});
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@
"lint": "eslint .",
"format": "prettier --write .",
"format:check": "prettier --check .",
"test": "bun test",
"check": "bun run typecheck && bun run lint && bun run format:check && bun run test"
"test": "bun test src",
"check": "bun run typecheck && bun run lint && bun run format:check && bun run test",
"test:e2e": "bun test e2e"
},
"dependencies": {
"arktype": "^2.2.3"
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
"lib": ["ESNext"],
"types": ["bun"]
},
"include": ["src"]
"include": ["src", "e2e"]
}
Loading