这是indexloc提供的服务,不要输入任何密码
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
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vibe-kit/grok-cli",
"version": "0.0.2",
"version": "0.0.3",
"description": "An open-source AI agent that brings the power of Grok directly into your terminal.",
"main": "dist/index.js",
"bin": {
Expand Down
22 changes: 17 additions & 5 deletions src/agent/grok-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createTokenCounter, TokenCounter } from "../utils/token-counter";
import { loadCustomInstructions } from "../utils/custom-instructions";

export interface ChatEntry {
type: "user" | "assistant" | "tool_result";
type: "user" | "assistant" | "tool_result" | "tool_call";
content: string;
timestamp: Date;
toolCalls?: GrokToolCall[];
Expand Down Expand Up @@ -64,6 +64,9 @@ You have access to these tools:
- create_todo_list: Create a visual todo list for planning and tracking tasks
- update_todo_list: Update existing todos in your todo list

REAL-TIME INFORMATION:
You have access to real-time web search and X (Twitter) data. When users ask for current information, latest news, or recent events, you automatically have access to up-to-date information from the web and social media.

IMPORTANT TOOL USAGE RULES:
- NEVER use create_file on files that already exist - this will overwrite them completely
- ALWAYS use str_replace_editor to modify existing files, even for small changes
Expand Down Expand Up @@ -127,7 +130,9 @@ Current working directory: ${process.cwd()}`,
try {
let currentResponse = await this.grokClient.chat(
this.messages,
GROK_TOOLS
GROK_TOOLS,
undefined,
{ search_parameters: { mode: "auto" } }
);

// Agent loop - continue until no more tool calls or max rounds reached
Expand Down Expand Up @@ -191,7 +196,9 @@ Current working directory: ${process.cwd()}`,
// Get next response - this might contain more tool calls
currentResponse = await this.grokClient.chat(
this.messages,
GROK_TOOLS
GROK_TOOLS,
undefined,
{ search_parameters: { mode: "auto" } }
);
} else {
// No more tool calls, add final response
Expand Down Expand Up @@ -270,7 +277,7 @@ Current working directory: ${process.cwd()}`,
): AsyncGenerator<StreamingChunk, void, unknown> {
// Create new abort controller for this request
this.abortController = new AbortController();

// Add user message to conversation
const userEntry: ChatEntry = {
type: "user",
Expand Down Expand Up @@ -307,7 +314,12 @@ Current working directory: ${process.cwd()}`,
}

// Stream response and accumulate
const stream = this.grokClient.chatStream(this.messages, GROK_TOOLS);
const stream = this.grokClient.chatStream(
this.messages,
GROK_TOOLS,
undefined,
{ search_parameters: { mode: "auto" } }
);
let accumulatedMessage: any = {};
let accumulatedContent = "";
let toolCallsYielded = false;
Expand Down
77 changes: 61 additions & 16 deletions src/grok/client.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import OpenAI from 'openai';
import type { ChatCompletionMessageParam } from 'openai/resources/chat';
import OpenAI from "openai";
import type { ChatCompletionMessageParam } from "openai/resources/chat";

export type GrokMessage = ChatCompletionMessageParam;

export interface GrokTool {
type: 'function';
type: "function";
function: {
name: string;
description: string;
parameters: {
type: 'object';
type: "object";
properties: Record<string, any>;
required: string[];
};
Expand All @@ -18,13 +18,22 @@ export interface GrokTool {

export interface GrokToolCall {
id: string;
type: 'function';
type: "function";
function: {
name: string;
arguments: string;
};
}

export interface SearchParameters {
mode?: "auto" | "on" | "off";
// sources removed - let API use default sources to avoid format issues
}

export interface SearchOptions {
search_parameters?: SearchParameters;
}

export interface GrokResponse {
choices: Array<{
message: {
Expand All @@ -38,12 +47,12 @@ export interface GrokResponse {

export class GrokClient {
private client: OpenAI;
private currentModel: string = 'grok-3-latest';
private currentModel: string = "grok-3-latest";

constructor(apiKey: string, model?: string, baseURL?: string) {
this.client = new OpenAI({
apiKey,
baseURL: baseURL || process.env.GROK_BASE_URL || 'https://api.x.ai/v1',
baseURL: baseURL || process.env.GROK_BASE_URL || "https://api.x.ai/v1",
timeout: 360000,
});
if (model) {
Expand All @@ -62,17 +71,27 @@ export class GrokClient {
async chat(
messages: GrokMessage[],
tools?: GrokTool[],
model?: string
model?: string,
searchOptions?: SearchOptions
): Promise<GrokResponse> {
try {
const response = await this.client.chat.completions.create({
const requestPayload: any = {
model: model || this.currentModel,
messages,
tools: tools || [],
tool_choice: tools ? 'auto' : undefined,
tool_choice: tools && tools.length > 0 ? "auto" : undefined,
temperature: 0.7,
max_tokens: 4000,
});
};

// Add search parameters if specified
if (searchOptions?.search_parameters) {
requestPayload.search_parameters = searchOptions.search_parameters;
}

const response = await this.client.chat.completions.create(
requestPayload
);

return response as GrokResponse;
} catch (error: any) {
Expand All @@ -83,18 +102,28 @@ export class GrokClient {
async *chatStream(
messages: GrokMessage[],
tools?: GrokTool[],
model?: string
model?: string,
searchOptions?: SearchOptions
): AsyncGenerator<any, void, unknown> {
try {
const stream = await this.client.chat.completions.create({
const requestPayload: any = {
model: model || this.currentModel,
messages,
tools: tools || [],
tool_choice: tools ? 'auto' : undefined,
tool_choice: tools && tools.length > 0 ? "auto" : undefined,
temperature: 0.7,
max_tokens: 4000,
stream: true,
});
};

// Add search parameters if specified
if (searchOptions?.search_parameters) {
requestPayload.search_parameters = searchOptions.search_parameters;
}

const stream = (await this.client.chat.completions.create(
requestPayload
)) as any;

for await (const chunk of stream) {
yield chunk;
Expand All @@ -103,4 +132,20 @@ export class GrokClient {
throw new Error(`Grok API error: ${error.message}`);
}
}
}

async search(
query: string,
searchParameters?: SearchParameters
): Promise<GrokResponse> {
const searchMessage: GrokMessage = {
role: "user",
content: query,
};

const searchOptions: SearchOptions = {
search_parameters: searchParameters || { mode: "on" },
};

return this.chat([searchMessage], [], undefined, searchOptions);
}
}
Loading
Loading