klaus-agent 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -15
- package/README.zh-CN.md +69 -15
- package/dist/core/agent-loop.d.ts +4 -1
- package/dist/core/agent-loop.js +20 -3
- package/dist/core/agent-loop.js.map +1 -1
- package/dist/core/agent.d.ts +5 -0
- package/dist/core/agent.js +25 -0
- package/dist/core/agent.js.map +1 -1
- package/dist/index.d.ts +10 -4
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/llm/provider.js +3 -11
- package/dist/llm/provider.js.map +1 -1
- package/dist/llm/types.d.ts +17 -0
- package/dist/planning/nag-injection.d.ts +8 -0
- package/dist/planning/nag-injection.js +21 -0
- package/dist/planning/nag-injection.js.map +1 -0
- package/dist/planning/planning-manager.d.ts +27 -0
- package/dist/planning/planning-manager.js +109 -0
- package/dist/planning/planning-manager.js.map +1 -0
- package/dist/planning/tools.d.ts +3 -0
- package/dist/planning/tools.js +50 -0
- package/dist/planning/tools.js.map +1 -0
- package/dist/planning/types.d.ts +30 -0
- package/dist/planning/types.js +6 -0
- package/dist/planning/types.js.map +1 -0
- package/dist/providers/openai-codex.js +1 -71
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/openai-responses-shared.d.ts +36 -0
- package/dist/providers/openai-responses-shared.js +74 -0
- package/dist/providers/openai-responses-shared.js.map +1 -0
- package/dist/providers/openai-responses.d.ts +7 -0
- package/dist/providers/openai-responses.js +128 -0
- package/dist/providers/openai-responses.js.map +1 -0
- package/dist/providers/openai.js +1 -10
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/shared.d.ts +5 -1
- package/dist/providers/shared.js +20 -0
- package/dist/providers/shared.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
- package/src/core/agent-loop.ts +25 -3
- package/src/core/agent.ts +30 -0
- package/src/index.ts +20 -3
- package/src/llm/provider.ts +3 -12
- package/src/llm/types.ts +19 -0
- package/src/planning/nag-injection.ts +24 -0
- package/src/planning/planning-manager.ts +133 -0
- package/src/planning/tools.ts +71 -0
- package/src/planning/types.ts +40 -0
- package/src/providers/openai-codex.ts +2 -89
- package/src/providers/openai-responses-shared.ts +97 -0
- package/src/providers/openai-responses.ts +152 -0
- package/src/providers/openai.ts +1 -8
- package/src/providers/shared.ts +19 -1
- package/src/types.ts +4 -0
- package/src/providers/index.ts +0 -7
- package/src/providers/kimi.ts +0 -12
- package/src/providers/minimax.ts +0 -12
- package/src/providers/volcengine.ts +0 -12
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// OpenAI Responses API provider
|
|
2
|
+
// Uses the official OpenAI SDK's client.responses.create() for streaming.
|
|
3
|
+
|
|
4
|
+
import OpenAI from "openai";
|
|
5
|
+
import type { ResponseCreateParamsStreaming, ResponseStreamEvent } from "openai/resources/responses/responses.js";
|
|
6
|
+
import type {
|
|
7
|
+
LLMProvider,
|
|
8
|
+
LLMRequestOptions,
|
|
9
|
+
AssistantMessageEvent,
|
|
10
|
+
AssistantMessage,
|
|
11
|
+
AssistantContentBlock,
|
|
12
|
+
TokenUsage,
|
|
13
|
+
ThinkingLevel,
|
|
14
|
+
} from "../llm/types.js";
|
|
15
|
+
import { withRetry, RETRYABLE_PATTERNS, mapReasoningEffort } from "./shared.js";
|
|
16
|
+
import { mapMessages, mapTools } from "./openai-responses-shared.js";
|
|
17
|
+
|
|
18
|
+
export class OpenAIResponsesProvider implements LLMProvider {
|
|
19
|
+
private client: OpenAI;
|
|
20
|
+
|
|
21
|
+
constructor(apiKey?: string, baseUrl?: string) {
|
|
22
|
+
this.client = new OpenAI({
|
|
23
|
+
apiKey: apiKey || process.env.OPENAI_API_KEY,
|
|
24
|
+
...(baseUrl ? { baseURL: baseUrl } : {}),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async *stream(options: LLMRequestOptions): AsyncIterable<AssistantMessageEvent> {
|
|
29
|
+
yield* withRetry(() => this._streamOnce(options), RETRYABLE_PATTERNS.openai);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private async *_streamOnce(options: LLMRequestOptions): AsyncIterable<AssistantMessageEvent> {
|
|
33
|
+
const { model, systemPrompt, messages, tools, thinkingLevel, maxTokens, signal } = options;
|
|
34
|
+
|
|
35
|
+
const effort = mapReasoningEffort(thinkingLevel);
|
|
36
|
+
|
|
37
|
+
const params: ResponseCreateParamsStreaming = {
|
|
38
|
+
model,
|
|
39
|
+
instructions: systemPrompt,
|
|
40
|
+
input: mapMessages(messages) as ResponseCreateParamsStreaming["input"],
|
|
41
|
+
stream: true,
|
|
42
|
+
store: false,
|
|
43
|
+
max_output_tokens: maxTokens ?? 8192,
|
|
44
|
+
include: ["reasoning.encrypted_content"],
|
|
45
|
+
...(tools?.length ? {
|
|
46
|
+
tools: mapTools(tools) as ResponseCreateParamsStreaming["tools"],
|
|
47
|
+
tool_choice: "auto" as const,
|
|
48
|
+
} : {}),
|
|
49
|
+
...(effort ? { reasoning: { effort, summary: "auto" as const } } : {}),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const contentBlocks: AssistantContentBlock[] = [];
|
|
53
|
+
const toolCalls = new Map<string, { id: string; name: string; args: string; callId: string }>();
|
|
54
|
+
let usage: TokenUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
55
|
+
|
|
56
|
+
const stream = await this.client.responses.create(params, { signal });
|
|
57
|
+
|
|
58
|
+
for await (const event of stream as AsyncIterable<ResponseStreamEvent>) {
|
|
59
|
+
const type = event.type;
|
|
60
|
+
|
|
61
|
+
// Text delta
|
|
62
|
+
if (type === "response.output_text.delta") {
|
|
63
|
+
const delta = event.delta;
|
|
64
|
+
if (delta) {
|
|
65
|
+
if (contentBlocks.length === 0 || contentBlocks[contentBlocks.length - 1].type !== "text") {
|
|
66
|
+
contentBlocks.push({ type: "text", text: "" });
|
|
67
|
+
}
|
|
68
|
+
const block = contentBlocks[contentBlocks.length - 1];
|
|
69
|
+
if (block.type === "text") block.text += delta;
|
|
70
|
+
yield { type: "text", text: delta };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Reasoning/thinking summary delta
|
|
75
|
+
if (type === "response.reasoning_summary_text.delta") {
|
|
76
|
+
const delta = event.delta;
|
|
77
|
+
if (delta) {
|
|
78
|
+
if (contentBlocks.length === 0 || contentBlocks[contentBlocks.length - 1].type !== "thinking") {
|
|
79
|
+
contentBlocks.push({ type: "thinking", thinking: "" });
|
|
80
|
+
}
|
|
81
|
+
const block = contentBlocks[contentBlocks.length - 1];
|
|
82
|
+
if (block.type === "thinking") block.thinking += delta;
|
|
83
|
+
yield { type: "thinking", thinking: delta };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// New output item (function call start)
|
|
88
|
+
if (type === "response.output_item.added") {
|
|
89
|
+
const item = event.item;
|
|
90
|
+
if (item?.type === "function_call") {
|
|
91
|
+
const id = item.id || item.call_id || `call_${toolCalls.size}`;
|
|
92
|
+
const callId = item.call_id || id;
|
|
93
|
+
const name = item.name || "";
|
|
94
|
+
toolCalls.set(id, { id, name, args: "", callId });
|
|
95
|
+
contentBlocks.push({ type: "tool_call", id: callId, name, input: {} });
|
|
96
|
+
yield { type: "tool_call_start", id: callId, name };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Function call arguments delta
|
|
101
|
+
if (type === "response.function_call_arguments.delta") {
|
|
102
|
+
const itemId = event.item_id;
|
|
103
|
+
const delta = event.delta;
|
|
104
|
+
if (itemId && delta) {
|
|
105
|
+
const entry = toolCalls.get(itemId);
|
|
106
|
+
if (entry) {
|
|
107
|
+
entry.args += delta;
|
|
108
|
+
yield { type: "tool_call_delta", id: entry.callId, input: delta };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Response completed or incomplete — extract usage
|
|
114
|
+
if (type === "response.completed" || type === "response.incomplete") {
|
|
115
|
+
const resp = event.response;
|
|
116
|
+
if (resp?.usage) {
|
|
117
|
+
usage = {
|
|
118
|
+
inputTokens: resp.usage.input_tokens ?? 0,
|
|
119
|
+
outputTokens: resp.usage.output_tokens ?? 0,
|
|
120
|
+
totalTokens: (resp.usage.input_tokens ?? 0) + (resp.usage.output_tokens ?? 0),
|
|
121
|
+
cacheReadTokens: resp.usage.input_tokens_details?.cached_tokens,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Error / failure
|
|
127
|
+
if (type === "error") {
|
|
128
|
+
const err = (event as any).error;
|
|
129
|
+
throw new Error(`OpenAI Responses error: ${err?.message || err?.code || JSON.stringify(event)}`);
|
|
130
|
+
}
|
|
131
|
+
if (type === "response.failed") {
|
|
132
|
+
const resp = event.response;
|
|
133
|
+
throw new Error(resp?.error?.message || "OpenAI Responses request failed");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Finalize tool call inputs
|
|
138
|
+
for (const [, entry] of toolCalls) {
|
|
139
|
+
const block = contentBlocks.find((b) => b.type === "tool_call" && b.id === entry.callId);
|
|
140
|
+
if (block && block.type === "tool_call") {
|
|
141
|
+
try {
|
|
142
|
+
block.input = JSON.parse(entry.args || "{}");
|
|
143
|
+
} catch {
|
|
144
|
+
block.input = {};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const message: AssistantMessage = { role: "assistant", content: contentBlocks };
|
|
150
|
+
yield { type: "done", message, usage };
|
|
151
|
+
}
|
|
152
|
+
}
|
package/src/providers/openai.ts
CHANGED
|
@@ -11,14 +11,7 @@ import type {
|
|
|
11
11
|
ThinkingLevel,
|
|
12
12
|
Message,
|
|
13
13
|
} from "../llm/types.js";
|
|
14
|
-
import { withRetry, RETRYABLE_PATTERNS } from "./shared.js";
|
|
15
|
-
|
|
16
|
-
function mapReasoningEffort(level?: ThinkingLevel): "low" | "medium" | "high" | undefined {
|
|
17
|
-
if (!level || level === "off") return undefined;
|
|
18
|
-
if (level === "minimal" || level === "low") return "low";
|
|
19
|
-
if (level === "medium") return "medium";
|
|
20
|
-
return "high";
|
|
21
|
-
}
|
|
14
|
+
import { withRetry, RETRYABLE_PATTERNS, mapReasoningEffort } from "./shared.js";
|
|
22
15
|
|
|
23
16
|
export class OpenAIProvider implements LLMProvider {
|
|
24
17
|
private client: OpenAI;
|
package/src/providers/shared.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Shared streaming utilities for LLM providers
|
|
2
2
|
|
|
3
|
-
import type { AssistantMessageEvent, ThinkingLevel } from "../llm/types.js";
|
|
3
|
+
import type { AssistantMessageEvent, ModelCost, TokenUsage, ThinkingLevel, UsageCost } from "../llm/types.js";
|
|
4
4
|
|
|
5
5
|
// Retryable error patterns common across providers
|
|
6
6
|
const COMMON_RETRYABLE = ["429", "500", "503", "ECONNRESET"];
|
|
@@ -59,3 +59,21 @@ export function mapThinkingBudget(level?: ThinkingLevel): number | undefined {
|
|
|
59
59
|
};
|
|
60
60
|
return budgets[level];
|
|
61
61
|
}
|
|
62
|
+
|
|
63
|
+
/** Maps ThinkingLevel to OpenAI reasoning_effort (shared by OpenAI and OpenAI Responses). */
|
|
64
|
+
export function mapReasoningEffort(level?: ThinkingLevel): "low" | "medium" | "high" | undefined {
|
|
65
|
+
if (!level || level === "off") return undefined;
|
|
66
|
+
if (level === "minimal" || level === "low") return "low";
|
|
67
|
+
if (level === "medium") return "medium";
|
|
68
|
+
return "high";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Calculate actual dollar cost from token counts and per-million-token pricing. */
|
|
72
|
+
export function calculateCost(cost: ModelCost | undefined, usage: TokenUsage): UsageCost | undefined {
|
|
73
|
+
if (!cost) return undefined;
|
|
74
|
+
const input = (cost.input / 1_000_000) * usage.inputTokens;
|
|
75
|
+
const output = (cost.output / 1_000_000) * usage.outputTokens;
|
|
76
|
+
const cacheRead = ((cost.cacheRead ?? 0) / 1_000_000) * (usage.cacheReadTokens ?? 0);
|
|
77
|
+
const cacheWrite = ((cost.cacheWrite ?? 0) / 1_000_000) * (usage.cacheWriteTokens ?? 0);
|
|
78
|
+
return { input, output, cacheRead, cacheWrite, total: input + output + cacheRead + cacheWrite };
|
|
79
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -7,6 +7,8 @@ import type {
|
|
|
7
7
|
ToolResultMessage,
|
|
8
8
|
AssistantMessageEvent,
|
|
9
9
|
TokenUsage,
|
|
10
|
+
ModelCost,
|
|
11
|
+
UsageCost,
|
|
10
12
|
ThinkingLevel,
|
|
11
13
|
ModelConfig,
|
|
12
14
|
ContentBlock,
|
|
@@ -78,6 +80,8 @@ export type {
|
|
|
78
80
|
ToolResultMessage,
|
|
79
81
|
AssistantMessageEvent,
|
|
80
82
|
TokenUsage,
|
|
83
|
+
ModelCost,
|
|
84
|
+
UsageCost,
|
|
81
85
|
ThinkingLevel,
|
|
82
86
|
ModelConfig,
|
|
83
87
|
ContentBlock,
|
package/src/providers/index.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { AnthropicProvider } from "./anthropic.js";
|
|
2
|
-
export { OpenAIProvider } from "./openai.js";
|
|
3
|
-
export { OpenAICodexProvider } from "./openai-codex.js";
|
|
4
|
-
export { GeminiProvider } from "./google.js";
|
|
5
|
-
export { MiniMaxProvider } from "./minimax.js";
|
|
6
|
-
export { KimiProvider } from "./kimi.js";
|
|
7
|
-
export { VolcengineProvider } from "./volcengine.js";
|
package/src/providers/kimi.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Kimi LLM provider (Anthropic Messages API compatible)
|
|
2
|
-
|
|
3
|
-
import { AnthropicProvider } from "./anthropic.js";
|
|
4
|
-
|
|
5
|
-
export class KimiProvider extends AnthropicProvider {
|
|
6
|
-
constructor(apiKey?: string, baseUrl?: string) {
|
|
7
|
-
super(
|
|
8
|
-
apiKey ?? process.env.KIMI_API_KEY,
|
|
9
|
-
baseUrl ?? "https://api.kimi.com/coding",
|
|
10
|
-
);
|
|
11
|
-
}
|
|
12
|
-
}
|
package/src/providers/minimax.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// MiniMax LLM provider (Anthropic Messages API compatible)
|
|
2
|
-
|
|
3
|
-
import { AnthropicProvider } from "./anthropic.js";
|
|
4
|
-
|
|
5
|
-
export class MiniMaxProvider extends AnthropicProvider {
|
|
6
|
-
constructor(apiKey?: string, baseUrl?: string) {
|
|
7
|
-
super(
|
|
8
|
-
apiKey ?? process.env.MINIMAX_API_KEY,
|
|
9
|
-
baseUrl ?? "https://api.minimaxi.com/anthropic",
|
|
10
|
-
);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Volcengine (Doubao) LLM provider (OpenAI Chat Completions API compatible)
|
|
2
|
-
|
|
3
|
-
import { OpenAIProvider } from "./openai.js";
|
|
4
|
-
|
|
5
|
-
export class VolcengineProvider extends OpenAIProvider {
|
|
6
|
-
constructor(apiKey?: string, baseUrl?: string) {
|
|
7
|
-
super(
|
|
8
|
-
apiKey ?? process.env.VOLCENGINE_API_KEY,
|
|
9
|
-
baseUrl ?? "https://ark.cn-beijing.volces.com/api/v3",
|
|
10
|
-
);
|
|
11
|
-
}
|
|
12
|
-
}
|