@kalenkevich/agent_007 0.0.1
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/dist/agent/agent.d.ts +17 -0
- package/dist/agent/agent.js +6 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/agent_event.d.ts +108 -0
- package/dist/agent/agent_event.js +56 -0
- package/dist/agent/agent_event.js.map +1 -0
- package/dist/agent/agent_event_utils.d.ts +5 -0
- package/dist/agent/agent_event_utils.js +66 -0
- package/dist/agent/agent_event_utils.js.map +1 -0
- package/dist/agent/cli_agent/cli_agent.d.ts +41 -0
- package/dist/agent/cli_agent/cli_agent.js +324 -0
- package/dist/agent/cli_agent/cli_agent.js.map +1 -0
- package/dist/agent/cli_agent/system_prompt.d.ts +1 -0
- package/dist/agent/cli_agent/system_prompt.js +58 -0
- package/dist/agent/cli_agent/system_prompt.js.map +1 -0
- package/dist/agent/cli_agent.d.ts +34 -0
- package/dist/agent/cli_agent.js +91 -0
- package/dist/agent/cli_agent.js.map +1 -0
- package/dist/agent/planner_agent/planner_agent.d.ts +28 -0
- package/dist/agent/planner_agent/planner_agent.js +102 -0
- package/dist/agent/planner_agent/planner_agent.js.map +1 -0
- package/dist/agent/request_processor/basic_request_processor.d.ts +17 -0
- package/dist/agent/request_processor/basic_request_processor.js +28 -0
- package/dist/agent/request_processor/basic_request_processor.js.map +1 -0
- package/dist/agent/request_processor/compaction_processor.d.ts +17 -0
- package/dist/agent/request_processor/compaction_processor.js +118 -0
- package/dist/agent/request_processor/compaction_processor.js.map +1 -0
- package/dist/agent/request_processor/request_processor.d.ts +11 -0
- package/dist/agent/request_processor/request_processor.js +2 -0
- package/dist/agent/request_processor/request_processor.js.map +1 -0
- package/dist/cli/init_project_command_handler.d.ts +3 -0
- package/dist/cli/init_project_command_handler.js +58 -0
- package/dist/cli/init_project_command_handler.js.map +1 -0
- package/dist/cli/loader.d.ts +6 -0
- package/dist/cli/loader.js +27 -0
- package/dist/cli/loader.js.map +1 -0
- package/dist/cli/prompt_utils.d.ts +11 -0
- package/dist/cli/prompt_utils.js +18 -0
- package/dist/cli/prompt_utils.js.map +1 -0
- package/dist/cli/run_command.d.ts +6 -0
- package/dist/cli/run_command.js +72 -0
- package/dist/cli/run_command.js.map +1 -0
- package/dist/cli/run_interactive_command.d.ts +6 -0
- package/dist/cli/run_interactive_command.js +282 -0
- package/dist/cli/run_interactive_command.js.map +1 -0
- package/dist/cli/run_noninteractive_command.d.ts +6 -0
- package/dist/cli/run_noninteractive_command.js +60 -0
- package/dist/cli/run_noninteractive_command.js.map +1 -0
- package/dist/cli_entrypoint.d.ts +2 -0
- package/dist/cli_entrypoint.js +110 -0
- package/dist/cli_entrypoint.js.map +1 -0
- package/dist/command/commnad_handler.d.ts +3 -0
- package/dist/command/commnad_handler.js +2 -0
- package/dist/command/commnad_handler.js.map +1 -0
- package/dist/command/init_project_command_handler.d.ts +4 -0
- package/dist/command/init_project_command_handler.js +58 -0
- package/dist/command/init_project_command_handler.js.map +1 -0
- package/dist/config/app_dir.d.ts +1 -0
- package/dist/config/app_dir.js +4 -0
- package/dist/config/app_dir.js.map +1 -0
- package/dist/config/config.d.ts +21 -0
- package/dist/config/config.js +2 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/config_loader.d.ts +2 -0
- package/dist/config/config_loader.js +47 -0
- package/dist/config/config_loader.js.map +1 -0
- package/dist/config/config_store.d.ts +10 -0
- package/dist/config/config_store.js +44 -0
- package/dist/config/config_store.js.map +1 -0
- package/dist/content.d.ts +51 -0
- package/dist/content.js +16 -0
- package/dist/content.js.map +1 -0
- package/dist/core/functions.d.ts +1 -0
- package/dist/core/functions.js +6 -0
- package/dist/core/functions.js.map +1 -0
- package/dist/core/loop.d.ts +20 -0
- package/dist/core/loop.js +121 -0
- package/dist/core/loop.js.map +1 -0
- package/dist/core/project_service.d.ts +11 -0
- package/dist/core/project_service.js +26 -0
- package/dist/core/project_service.js.map +1 -0
- package/dist/core/run.d.ts +6 -0
- package/dist/core/run.js +25 -0
- package/dist/core/run.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +27 -0
- package/dist/logger.js +98 -0
- package/dist/logger.js.map +1 -0
- package/dist/model/adaptive_model.d.ts +16 -0
- package/dist/model/adaptive_model.js +57 -0
- package/dist/model/adaptive_model.js.map +1 -0
- package/dist/model/google/gemini_model.d.ts +15 -0
- package/dist/model/google/gemini_model.js +131 -0
- package/dist/model/google/gemini_model.js.map +1 -0
- package/dist/model/google/gemini_response_utils.d.ts +3 -0
- package/dist/model/google/gemini_response_utils.js +36 -0
- package/dist/model/google/gemini_response_utils.js.map +1 -0
- package/dist/model/google/gemini_streaming_utils.d.ts +28 -0
- package/dist/model/google/gemini_streaming_utils.js +235 -0
- package/dist/model/google/gemini_streaming_utils.js.map +1 -0
- package/dist/model/google/gen_ai_convert_utils.d.ts +6 -0
- package/dist/model/google/gen_ai_convert_utils.js +117 -0
- package/dist/model/google/gen_ai_convert_utils.js.map +1 -0
- package/dist/model/model.d.ts +11 -0
- package/dist/model/model.js +2 -0
- package/dist/model/model.js.map +1 -0
- package/dist/model/registry.d.ts +19 -0
- package/dist/model/registry.js +47 -0
- package/dist/model/registry.js.map +1 -0
- package/dist/model/request.d.ts +13 -0
- package/dist/model/request.js +2 -0
- package/dist/model/request.js.map +1 -0
- package/dist/model/request_builder_utils.d.ts +19 -0
- package/dist/model/request_builder_utils.js +43 -0
- package/dist/model/request_builder_utils.js.map +1 -0
- package/dist/model/response.d.ts +60 -0
- package/dist/model/response.js +2 -0
- package/dist/model/response.js.map +1 -0
- package/dist/model/util_llm.d.ts +10 -0
- package/dist/model/util_llm.js +149 -0
- package/dist/model/util_llm.js.map +1 -0
- package/dist/session/session.d.ts +14 -0
- package/dist/session/session.js +2 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/session_file_service.d.ts +23 -0
- package/dist/session/session_file_service.js +147 -0
- package/dist/session/session_file_service.js.map +1 -0
- package/dist/skills/skill.d.ts +23 -0
- package/dist/skills/skill.js +12 -0
- package/dist/skills/skill.js.map +1 -0
- package/dist/tools/build_in/find.d.ts +3 -0
- package/dist/tools/build_in/find.js +71 -0
- package/dist/tools/build_in/find.js.map +1 -0
- package/dist/tools/build_in/grep.d.ts +3 -0
- package/dist/tools/build_in/grep.js +97 -0
- package/dist/tools/build_in/grep.js.map +1 -0
- package/dist/tools/build_in/index.d.ts +1 -0
- package/dist/tools/build_in/index.js +13 -0
- package/dist/tools/build_in/index.js.map +1 -0
- package/dist/tools/build_in/list_dir.d.ts +3 -0
- package/dist/tools/build_in/list_dir.js +46 -0
- package/dist/tools/build_in/list_dir.js.map +1 -0
- package/dist/tools/build_in/view_file.d.ts +3 -0
- package/dist/tools/build_in/view_file.js +44 -0
- package/dist/tools/build_in/view_file.js.map +1 -0
- package/dist/tools/build_in/write_file.d.ts +3 -0
- package/dist/tools/build_in/write_file.js +50 -0
- package/dist/tools/build_in/write_file.js.map +1 -0
- package/dist/tools/functional_tool.d.ts +18 -0
- package/dist/tools/functional_tool.js +20 -0
- package/dist/tools/functional_tool.js.map +1 -0
- package/dist/tools/schema.d.ts +86 -0
- package/dist/tools/schema.js +37 -0
- package/dist/tools/schema.js.map +1 -0
- package/dist/tools/tool.d.ts +30 -0
- package/dist/tools/tool.js +9 -0
- package/dist/tools/tool.js.map +1 -0
- package/dist/tools/tool_call_policy.d.ts +4 -0
- package/dist/tools/tool_call_policy.js +4 -0
- package/dist/tools/tool_call_policy.js.map +1 -0
- package/dist/tools/tool_policy.d.ts +4 -0
- package/dist/tools/tool_policy.js +4 -0
- package/dist/tools/tool_policy.js.map +1 -0
- package/dist/ui/ui.d.ts +1 -0
- package/dist/ui/ui.js +2 -0
- package/dist/ui/ui.js.map +1 -0
- package/dist/user_input.d.ts +20 -0
- package/dist/user_input.js +21 -0
- package/dist/user_input.js.map +1 -0
- package/package.json +44 -0
- package/src/agent/agent.ts +18 -0
- package/src/agent/agent_event.ts +171 -0
- package/src/agent/agent_event_utils.ts +87 -0
- package/src/agent/cli_agent/cli_agent.ts +418 -0
- package/src/agent/cli_agent/system_prompt.ts +57 -0
- package/src/agent/planner_agent/planner_agent.ts +136 -0
- package/src/agent/request_processor/basic_request_processor.ts +46 -0
- package/src/agent/request_processor/compaction_processor.ts +164 -0
- package/src/agent/request_processor/request_processor.ts +13 -0
- package/src/cli/loader.ts +27 -0
- package/src/cli/prompt_utils.ts +19 -0
- package/src/cli/run_interactive_command.ts +337 -0
- package/src/cli/run_noninteractive_command.ts +74 -0
- package/src/cli_entrypoint.ts +128 -0
- package/src/command/commnad_handler.ts +3 -0
- package/src/command/init_project_command_handler.ts +66 -0
- package/src/config/app_dir.ts +4 -0
- package/src/config/config.ts +24 -0
- package/src/config/config_loader.ts +57 -0
- package/src/config/config_store.ts +50 -0
- package/src/content.ts +87 -0
- package/src/core/functions.ts +7 -0
- package/src/core/loop.ts +165 -0
- package/src/core/project_service.ts +38 -0
- package/src/core/run.ts +36 -0
- package/src/index.ts +1 -0
- package/src/logger.ts +128 -0
- package/src/model/adaptive_model.ts +77 -0
- package/src/model/google/gemini_model.ts +194 -0
- package/src/model/google/gemini_response_utils.ts +46 -0
- package/src/model/google/gemini_streaming_utils.ts +294 -0
- package/src/model/google/gen_ai_convert_utils.ts +149 -0
- package/src/model/model.ts +18 -0
- package/src/model/registry.ts +61 -0
- package/src/model/request.ts +15 -0
- package/src/model/request_builder_utils.ts +79 -0
- package/src/model/response.ts +66 -0
- package/src/model/util_llm.ts +167 -0
- package/src/session/session.ts +16 -0
- package/src/session/session_file_service.ts +207 -0
- package/src/skills/skill.ts +38 -0
- package/src/tools/build_in/find.ts +80 -0
- package/src/tools/build_in/grep.ts +101 -0
- package/src/tools/build_in/index.ts +13 -0
- package/src/tools/build_in/list_dir.ts +50 -0
- package/src/tools/build_in/view_file.ts +47 -0
- package/src/tools/build_in/write_file.ts +53 -0
- package/src/tools/functional_tool.ts +59 -0
- package/src/tools/schema.ts +87 -0
- package/src/tools/tool.ts +68 -0
- package/src/tools/tool_call_policy.ts +7 -0
- package/src/ui/ui.ts +0 -0
- package/src/user_input.ts +51 -0
- package/tests/integration/util_llm_test.ts +42 -0
- package/tests/unit/adaptive_model_test.ts +122 -0
- package/tests/unit/agent/request_processor/compaction_processor_test.ts +121 -0
- package/tests/unit/cli/prompt_utils_test.ts +47 -0
- package/tests/unit/cli_agent_test.ts +476 -0
- package/tests/unit/content_test.ts +56 -0
- package/tests/unit/logger_test.ts +109 -0
- package/tests/unit/loop_test.ts +141 -0
- package/tests/unit/model/gemini_model_test.ts +111 -0
- package/tests/unit/planner_agent_test.ts +52 -0
- package/tests/unit/project_service_test.ts +102 -0
- package/tests/unit/session_file_service_test.ts +160 -0
- package/tests/unit/tools/find_test.ts +40 -0
- package/tests/unit/tools/grep_test.ts +43 -0
- package/tests/unit/tools/list_dir_test.ts +32 -0
- package/tests/unit/tools/view_file_test.ts +32 -0
- package/tests/unit/tools/write_file_test.ts +44 -0
- package/tests/unit/user_input_test.ts +55 -0
- package/tests/unit/util_llm_test.ts +61 -0
- package/todo.md +29 -0
- package/tsconfig.json +33 -0
- package/vitest.config.ts +33 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { GenerateContentResponse, FinishReason } from "@google/genai";
|
|
2
|
+
import { generateClientFunctionCallId } from "../../core/functions.js";
|
|
3
|
+
import type { LlmResponse, UsageMetadata } from "../response.js";
|
|
4
|
+
import {
|
|
5
|
+
type ContentPart,
|
|
6
|
+
type PartialArg,
|
|
7
|
+
type FunctionCallContentPart,
|
|
8
|
+
isTextContentPart,
|
|
9
|
+
isThoughtContentPart,
|
|
10
|
+
isFunctionCallContentPart,
|
|
11
|
+
} from "../../content.js";
|
|
12
|
+
import { createLlmResponse } from "./gemini_response_utils.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Aggregates partial streaming responses.
|
|
16
|
+
*
|
|
17
|
+
* It aggregates content from partial responses, and generates LlmResponses for
|
|
18
|
+
* individual (partial) model responses, as well as for aggregated content.
|
|
19
|
+
*/
|
|
20
|
+
export class StreamingResponseAggregator {
|
|
21
|
+
private usageMetadata?: UsageMetadata;
|
|
22
|
+
// private groundingMetadata?: GroundingMetadata;
|
|
23
|
+
// private citationMetadata?: CitationMetadata;
|
|
24
|
+
private response?: GenerateContentResponse;
|
|
25
|
+
|
|
26
|
+
// For progressive SSE streaming mode: accumulate parts in order
|
|
27
|
+
private partsSequence: ContentPart[] = [];
|
|
28
|
+
private currentTextBuffer = "";
|
|
29
|
+
private currentTextIsThought?: boolean;
|
|
30
|
+
private finishReason?: string;
|
|
31
|
+
|
|
32
|
+
// For streaming function call arguments
|
|
33
|
+
private currentFcName?: string;
|
|
34
|
+
private currentFcArgs: Record<string, unknown> = {};
|
|
35
|
+
private currentFcId?: string;
|
|
36
|
+
private currentThoughtSignature?: string | Uint8Array;
|
|
37
|
+
|
|
38
|
+
private flushTextBufferToSequence(): void {
|
|
39
|
+
if (!this.currentTextBuffer) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (this.currentTextIsThought) {
|
|
44
|
+
this.partsSequence.push({
|
|
45
|
+
type: "thought",
|
|
46
|
+
thought: this.currentTextBuffer,
|
|
47
|
+
});
|
|
48
|
+
} else {
|
|
49
|
+
this.partsSequence.push({
|
|
50
|
+
type: "text",
|
|
51
|
+
text: this.currentTextBuffer,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.currentTextBuffer = "";
|
|
56
|
+
this.currentTextIsThought = undefined;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private getValueFromPartialArg(
|
|
60
|
+
partialArg: PartialArg,
|
|
61
|
+
jsonPath: string,
|
|
62
|
+
): [unknown, boolean] {
|
|
63
|
+
let value: unknown = null;
|
|
64
|
+
let hasValue = false;
|
|
65
|
+
|
|
66
|
+
const stringValue = partialArg.stringValue;
|
|
67
|
+
const numberValue = partialArg.numberValue;
|
|
68
|
+
const boolValue = partialArg.boolValue;
|
|
69
|
+
const nullValue = partialArg.nullValue;
|
|
70
|
+
|
|
71
|
+
if (stringValue !== undefined) {
|
|
72
|
+
const stringChunk = stringValue;
|
|
73
|
+
hasValue = true;
|
|
74
|
+
|
|
75
|
+
const pathWithoutPrefix = jsonPath.startsWith("$.")
|
|
76
|
+
? jsonPath.slice(2)
|
|
77
|
+
: jsonPath;
|
|
78
|
+
const pathParts = pathWithoutPrefix.split(".");
|
|
79
|
+
|
|
80
|
+
let existingValue = this.currentFcArgs;
|
|
81
|
+
for (const part of pathParts) {
|
|
82
|
+
if (
|
|
83
|
+
existingValue &&
|
|
84
|
+
typeof existingValue === "object" &&
|
|
85
|
+
part in existingValue
|
|
86
|
+
) {
|
|
87
|
+
existingValue = existingValue[part] as Record<string, unknown>;
|
|
88
|
+
} else {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (typeof existingValue === "string") {
|
|
94
|
+
value = existingValue + stringChunk;
|
|
95
|
+
} else {
|
|
96
|
+
value = stringChunk;
|
|
97
|
+
}
|
|
98
|
+
} else if (numberValue !== undefined) {
|
|
99
|
+
value = numberValue;
|
|
100
|
+
hasValue = true;
|
|
101
|
+
} else if (boolValue !== undefined) {
|
|
102
|
+
value = boolValue;
|
|
103
|
+
hasValue = true;
|
|
104
|
+
} else if (nullValue !== undefined) {
|
|
105
|
+
value = null;
|
|
106
|
+
hasValue = true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return [value, hasValue];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private setValueByJsonPath(jsonPath: string, value: unknown): void {
|
|
113
|
+
const path = jsonPath.startsWith("$.") ? jsonPath.slice(2) : jsonPath;
|
|
114
|
+
const pathParts = path.split(".");
|
|
115
|
+
|
|
116
|
+
let current = this.currentFcArgs;
|
|
117
|
+
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
118
|
+
const part = pathParts[i];
|
|
119
|
+
if (!(part in current)) {
|
|
120
|
+
current[part] = {};
|
|
121
|
+
}
|
|
122
|
+
current = current[part] as Record<string, unknown>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
current[pathParts[pathParts.length - 1]] = value;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private flushFunctionCallToSequence(): void {
|
|
129
|
+
if (this.currentFcName) {
|
|
130
|
+
const fcPart: FunctionCallContentPart = {
|
|
131
|
+
type: "function_call",
|
|
132
|
+
name: this.currentFcName,
|
|
133
|
+
args: JSON.parse(JSON.stringify(this.currentFcArgs)),
|
|
134
|
+
id: this.currentFcId ?? generateClientFunctionCallId(),
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
if (this.currentThoughtSignature) {
|
|
138
|
+
fcPart.thoughtSignature = this.currentThoughtSignature.toString();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.partsSequence.push(fcPart);
|
|
142
|
+
|
|
143
|
+
this.currentFcName = undefined;
|
|
144
|
+
this.currentFcArgs = {};
|
|
145
|
+
this.currentFcId = undefined;
|
|
146
|
+
this.currentThoughtSignature = undefined;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private processStreamingFunctionCall(fc: FunctionCallContentPart): void {
|
|
151
|
+
if (fc.name) {
|
|
152
|
+
this.currentFcName = fc.name;
|
|
153
|
+
}
|
|
154
|
+
if (fc.id) {
|
|
155
|
+
this.currentFcId = fc.id;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
for (const partialArg of fc.partialArgs || []) {
|
|
159
|
+
const jsonPath = partialArg.jsonPath;
|
|
160
|
+
if (!jsonPath) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const [value, hasValue] = this.getValueFromPartialArg(
|
|
165
|
+
partialArg,
|
|
166
|
+
jsonPath,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (hasValue) {
|
|
170
|
+
this.setValueByJsonPath(jsonPath, value);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!fc.willContinue) {
|
|
175
|
+
this.flushTextBufferToSequence();
|
|
176
|
+
this.flushFunctionCallToSequence();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private processFunctionCallPart(part: FunctionCallContentPart): void {
|
|
181
|
+
const fc = part;
|
|
182
|
+
|
|
183
|
+
if (fc.partialArgs || fc.willContinue) {
|
|
184
|
+
if (!fc.id && !this.currentFcId) {
|
|
185
|
+
fc.id = generateClientFunctionCallId();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (part.thoughtSignature && !this.currentThoughtSignature) {
|
|
189
|
+
this.currentThoughtSignature = part.thoughtSignature;
|
|
190
|
+
}
|
|
191
|
+
this.processStreamingFunctionCall(fc);
|
|
192
|
+
} else {
|
|
193
|
+
if (fc.name) {
|
|
194
|
+
if (!fc.id) {
|
|
195
|
+
fc.id = generateClientFunctionCallId();
|
|
196
|
+
}
|
|
197
|
+
this.flushTextBufferToSequence();
|
|
198
|
+
this.partsSequence.push(part);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async *processResponse(
|
|
204
|
+
response: GenerateContentResponse,
|
|
205
|
+
): AsyncGenerator<LlmResponse, void, void> {
|
|
206
|
+
this.response = response;
|
|
207
|
+
const llmResponse = createLlmResponse(response);
|
|
208
|
+
this.usageMetadata = llmResponse.usageMetadata;
|
|
209
|
+
// if (llmResponse.groundingMetadata) {
|
|
210
|
+
// this.groundingMetadata = llmResponse.groundingMetadata;
|
|
211
|
+
// }
|
|
212
|
+
// if (llmResponse.citationMetadata) {
|
|
213
|
+
// this.citationMetadata = llmResponse.citationMetadata;
|
|
214
|
+
// }
|
|
215
|
+
|
|
216
|
+
if (llmResponse.finishReason) {
|
|
217
|
+
this.finishReason = llmResponse.finishReason;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (llmResponse.content && llmResponse.content.parts) {
|
|
221
|
+
for (const part of llmResponse.content.parts) {
|
|
222
|
+
if (isTextContentPart(part)) {
|
|
223
|
+
const isThought = false;
|
|
224
|
+
if (
|
|
225
|
+
this.currentTextBuffer &&
|
|
226
|
+
isThought !== this.currentTextIsThought
|
|
227
|
+
) {
|
|
228
|
+
this.flushTextBufferToSequence();
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (!this.currentTextBuffer) {
|
|
232
|
+
this.currentTextIsThought = isThought;
|
|
233
|
+
}
|
|
234
|
+
this.currentTextBuffer += part.text;
|
|
235
|
+
} else if (isThoughtContentPart(part)) {
|
|
236
|
+
const isThought = true;
|
|
237
|
+
if (
|
|
238
|
+
this.currentTextBuffer &&
|
|
239
|
+
isThought !== this.currentTextIsThought
|
|
240
|
+
) {
|
|
241
|
+
this.flushTextBufferToSequence();
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (!this.currentTextBuffer) {
|
|
245
|
+
this.currentTextIsThought = isThought;
|
|
246
|
+
}
|
|
247
|
+
this.currentTextBuffer += part.thought;
|
|
248
|
+
} else if (isFunctionCallContentPart(part)) {
|
|
249
|
+
this.processFunctionCallPart(part);
|
|
250
|
+
} else {
|
|
251
|
+
this.flushTextBufferToSequence();
|
|
252
|
+
this.partsSequence.push(part);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
llmResponse.partial = true;
|
|
258
|
+
yield llmResponse;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
close(): LlmResponse | undefined {
|
|
262
|
+
if (!this.response?.candidates || this.response.candidates.length === 0) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
this.flushTextBufferToSequence();
|
|
267
|
+
this.flushFunctionCallToSequence();
|
|
268
|
+
|
|
269
|
+
const finalParts = this.partsSequence;
|
|
270
|
+
if (finalParts.length === 0) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const candidate = this.response.candidates[0];
|
|
275
|
+
const finishReason = this.finishReason ?? candidate.finishReason;
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
content: {
|
|
279
|
+
role: "agent",
|
|
280
|
+
parts: finalParts,
|
|
281
|
+
},
|
|
282
|
+
// groundingMetadata: this.groundingMetadata,
|
|
283
|
+
// citationMetadata: this.citationMetadata,
|
|
284
|
+
errorCode: finishReason === FinishReason.STOP ? undefined : finishReason,
|
|
285
|
+
errorMessage:
|
|
286
|
+
finishReason === FinishReason.STOP
|
|
287
|
+
? undefined
|
|
288
|
+
: candidate.finishMessage,
|
|
289
|
+
usageMetadata: this.usageMetadata,
|
|
290
|
+
finishReason: finishReason,
|
|
291
|
+
partial: false,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Content,
|
|
3
|
+
type ContentPart,
|
|
4
|
+
isTextContentPart,
|
|
5
|
+
isThoughtContentPart,
|
|
6
|
+
isMediaContentPart,
|
|
7
|
+
isFunctionCallContentPart,
|
|
8
|
+
isFunctionResponseContentPart,
|
|
9
|
+
} from "../../content.js";
|
|
10
|
+
import type {
|
|
11
|
+
Part as GenAIContentPart,
|
|
12
|
+
Content as GenAIContent,
|
|
13
|
+
} from "@google/genai";
|
|
14
|
+
|
|
15
|
+
export function contentToGenAIContent(content: Content): GenAIContent {
|
|
16
|
+
return {
|
|
17
|
+
parts: content.parts.map((part) => contentPartToGenAIContentPart(part)),
|
|
18
|
+
role: content.role === "user" ? "user" : "model",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function contentPartToGenAIContentPart(
|
|
23
|
+
part: ContentPart,
|
|
24
|
+
): GenAIContentPart {
|
|
25
|
+
if (isTextContentPart(part)) {
|
|
26
|
+
return {
|
|
27
|
+
text: part.text,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (isThoughtContentPart(part)) {
|
|
32
|
+
return {
|
|
33
|
+
text: part.thought,
|
|
34
|
+
thought: true,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isMediaContentPart(part) && part.data) {
|
|
39
|
+
return {
|
|
40
|
+
inlineData: {
|
|
41
|
+
data: part.data,
|
|
42
|
+
mimeType: part.mimeType,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (isMediaContentPart(part) && part.uri) {
|
|
48
|
+
return {
|
|
49
|
+
fileData: {
|
|
50
|
+
fileUri: part.uri,
|
|
51
|
+
mimeType: part.mimeType,
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (isFunctionCallContentPart(part)) {
|
|
57
|
+
return {
|
|
58
|
+
functionCall: {
|
|
59
|
+
id: part.id,
|
|
60
|
+
name: part.name,
|
|
61
|
+
args: part.args,
|
|
62
|
+
partialArgs: part.partialArgs,
|
|
63
|
+
willContinue: part.willContinue,
|
|
64
|
+
},
|
|
65
|
+
thoughtSignature: part.thoughtSignature,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (isFunctionResponseContentPart(part)) {
|
|
70
|
+
return {
|
|
71
|
+
functionResponse: {
|
|
72
|
+
id: part.id,
|
|
73
|
+
name: part.name,
|
|
74
|
+
response: part.response,
|
|
75
|
+
willContinue: part.willContinue,
|
|
76
|
+
},
|
|
77
|
+
thoughtSignature: part.thoughtSignature,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
throw new Error(`Unsupported content type: ${part.type}`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function genAIContentToContent(genAIContent: GenAIContent): Content {
|
|
85
|
+
return {
|
|
86
|
+
role: genAIContent.role === "user" ? "user" : "agent",
|
|
87
|
+
parts: (genAIContent.parts || []).map((p) =>
|
|
88
|
+
genAIContentPartToContentPart(p),
|
|
89
|
+
),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function genAIContentPartToContentPart(
|
|
94
|
+
part: GenAIContentPart,
|
|
95
|
+
): ContentPart {
|
|
96
|
+
if (part.text !== undefined) {
|
|
97
|
+
if ((part as any).thought) {
|
|
98
|
+
return {
|
|
99
|
+
type: "thought",
|
|
100
|
+
thought: part.text,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
type: "text",
|
|
105
|
+
text: part.text,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (part.inlineData) {
|
|
110
|
+
return {
|
|
111
|
+
type: "media",
|
|
112
|
+
data: part.inlineData.data,
|
|
113
|
+
mimeType: part.inlineData.mimeType,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (part.fileData) {
|
|
118
|
+
return {
|
|
119
|
+
type: "media",
|
|
120
|
+
uri: part.fileData.fileUri,
|
|
121
|
+
mimeType: part.fileData.mimeType,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (part.functionCall) {
|
|
126
|
+
return {
|
|
127
|
+
type: "function_call",
|
|
128
|
+
id: part.functionCall.id,
|
|
129
|
+
name: part.functionCall.name,
|
|
130
|
+
args: part.functionCall.args,
|
|
131
|
+
partialArgs: part.functionCall.partialArgs,
|
|
132
|
+
willContinue: part.functionCall.willContinue,
|
|
133
|
+
thoughtSignature: part.thoughtSignature,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (part.functionResponse) {
|
|
138
|
+
return {
|
|
139
|
+
type: "function_response",
|
|
140
|
+
id: part.functionResponse.id,
|
|
141
|
+
name: part.functionResponse.name,
|
|
142
|
+
response: part.functionResponse.response,
|
|
143
|
+
willContinue: part.functionResponse.willContinue,
|
|
144
|
+
thoughtSignature: part.thoughtSignature,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
throw new Error(`Unsupported GenAI content part`);
|
|
149
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LlmRequest } from "./request.js";
|
|
2
|
+
import type { LlmResponse } from "./response.js";
|
|
3
|
+
|
|
4
|
+
export interface LlmModelConfig {
|
|
5
|
+
stream?: boolean;
|
|
6
|
+
abortSignal?: AbortSignal;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface LlmModel {
|
|
10
|
+
modelName: string;
|
|
11
|
+
|
|
12
|
+
run(
|
|
13
|
+
request: LlmRequest,
|
|
14
|
+
config?: LlmModelConfig,
|
|
15
|
+
): AsyncGenerator<LlmResponse, void, unknown>;
|
|
16
|
+
|
|
17
|
+
countTokens(request: LlmRequest): Promise<number>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { LlmModel } from "./model.js";
|
|
2
|
+
import { Gemini } from "./google/gemini_model.js";
|
|
3
|
+
|
|
4
|
+
type LlmModelClass = {
|
|
5
|
+
new (params: { modelName: string; apiKey: string }): LlmModel;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export enum ModelType {
|
|
9
|
+
LITE = "lite",
|
|
10
|
+
FAST = "fast",
|
|
11
|
+
PRO = "pro",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ModelInfo {
|
|
15
|
+
name: string;
|
|
16
|
+
type: ModelType;
|
|
17
|
+
klass: LlmModelClass;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const MODEL_REGISTRY: Record<string, ModelInfo> = {
|
|
21
|
+
"gemini-3.1-pro-preview": {
|
|
22
|
+
name: "gemini-3.1-pro-preview",
|
|
23
|
+
type: ModelType.PRO,
|
|
24
|
+
klass: Gemini,
|
|
25
|
+
},
|
|
26
|
+
"gemini-3-flash-preview": {
|
|
27
|
+
name: "gemini-3-flash-preview",
|
|
28
|
+
type: ModelType.FAST,
|
|
29
|
+
klass: Gemini,
|
|
30
|
+
},
|
|
31
|
+
"gemini-3.1-flash-lite-preview": {
|
|
32
|
+
name: "gemini-3.1-flash-lite-preview",
|
|
33
|
+
type: ModelType.LITE,
|
|
34
|
+
klass: Gemini,
|
|
35
|
+
},
|
|
36
|
+
"gemini-2.5-pro": {
|
|
37
|
+
name: "gemini-2.5-pro",
|
|
38
|
+
type: ModelType.PRO,
|
|
39
|
+
klass: Gemini,
|
|
40
|
+
},
|
|
41
|
+
"gemini-2.5-flash": {
|
|
42
|
+
name: "gemini-2.5-flash",
|
|
43
|
+
type: ModelType.FAST,
|
|
44
|
+
klass: Gemini,
|
|
45
|
+
},
|
|
46
|
+
"gemini-2.5-flash-lite": {
|
|
47
|
+
name: "gemini-2.5-flash-lite",
|
|
48
|
+
type: ModelType.LITE,
|
|
49
|
+
klass: Gemini,
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
export function resolveLlmModel(modelName: string): LlmModelClass {
|
|
54
|
+
const modelInfo = MODEL_REGISTRY[modelName];
|
|
55
|
+
|
|
56
|
+
if (!modelInfo) {
|
|
57
|
+
throw new Error(`Model ${modelName} not found`);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return modelInfo.klass;
|
|
61
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Content } from "../content.js";
|
|
2
|
+
import type { FunctionDeclaration } from "../tools/tool.js";
|
|
3
|
+
|
|
4
|
+
export interface LlmRequest {
|
|
5
|
+
model?: string;
|
|
6
|
+
contents: Content[];
|
|
7
|
+
systemInstructions?: string;
|
|
8
|
+
tools?: FunctionDeclaration[];
|
|
9
|
+
thinkingConfig?: ThinkingConfig;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ThinkingConfig {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
level?: "low" | "medium" | "high" | "auto";
|
|
15
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { LlmRequest, ThinkingConfig } from "./request.js";
|
|
2
|
+
import type { Content } from "../content.js";
|
|
3
|
+
import type { Tool, FunctionDeclaration } from "../tools/tool.js";
|
|
4
|
+
import { type Skill, toFunctionDeclaration } from "../skills/skill.js";
|
|
5
|
+
|
|
6
|
+
interface BuildLlmRequestOptions {
|
|
7
|
+
agentName: string;
|
|
8
|
+
content: Content;
|
|
9
|
+
historyContent: Content[];
|
|
10
|
+
tools?: Tool[];
|
|
11
|
+
skills?: Skill[];
|
|
12
|
+
description?: string;
|
|
13
|
+
instructions: string;
|
|
14
|
+
thinkingConfig?: ThinkingConfig;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function buildLlmRequest(options: BuildLlmRequestOptions): LlmRequest {
|
|
18
|
+
const {
|
|
19
|
+
agentName,
|
|
20
|
+
content,
|
|
21
|
+
historyContent,
|
|
22
|
+
tools,
|
|
23
|
+
skills,
|
|
24
|
+
description,
|
|
25
|
+
instructions,
|
|
26
|
+
thinkingConfig,
|
|
27
|
+
} = options;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
contents: mergeAdjacentContents([...historyContent, content]),
|
|
31
|
+
tools: [...buildTools(tools), ...buildSkillsTools(skills)],
|
|
32
|
+
systemInstructions: buildSystemInstruction(
|
|
33
|
+
agentName,
|
|
34
|
+
description,
|
|
35
|
+
instructions,
|
|
36
|
+
),
|
|
37
|
+
thinkingConfig,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function mergeAdjacentContents(contents: Content[]): Content[] {
|
|
42
|
+
const result: Content[] = [];
|
|
43
|
+
for (const content of contents) {
|
|
44
|
+
const last = result[result.length - 1];
|
|
45
|
+
if (last && last.role === content.role) {
|
|
46
|
+
last.parts.push(...content.parts);
|
|
47
|
+
} else {
|
|
48
|
+
result.push({ ...content, parts: [...content.parts] });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function buildTools(tools?: Tool[]): FunctionDeclaration[] {
|
|
56
|
+
if (!tools) return [];
|
|
57
|
+
|
|
58
|
+
return tools.map((t) => t.toFunctionDeclaration());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function buildSkillsTools(skills?: Skill[]): FunctionDeclaration[] {
|
|
62
|
+
if (!skills) return [];
|
|
63
|
+
|
|
64
|
+
return skills.map((skill) => toFunctionDeclaration(skill));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function buildSystemInstruction(
|
|
68
|
+
name: string,
|
|
69
|
+
description: string | undefined,
|
|
70
|
+
instructions: string,
|
|
71
|
+
): string {
|
|
72
|
+
return [
|
|
73
|
+
`You are an agent. Your internal name is "${name}".`,
|
|
74
|
+
description ? `The description about you is "${description}"` : "",
|
|
75
|
+
instructions,
|
|
76
|
+
]
|
|
77
|
+
.filter(Boolean)
|
|
78
|
+
.join("\n\n");
|
|
79
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Content } from "../content.js";
|
|
2
|
+
|
|
3
|
+
export interface UsageMetadata {
|
|
4
|
+
inputTokens?: number;
|
|
5
|
+
outputTokens?: number;
|
|
6
|
+
cachedTokens?: number;
|
|
7
|
+
cost?: { amount: number; currency?: string };
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type FinishReason = string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* LLM response class that provides the first candidate response from the
|
|
14
|
+
* model if available. Otherwise, returns error code and message.
|
|
15
|
+
*/
|
|
16
|
+
export interface LlmResponse {
|
|
17
|
+
/**
|
|
18
|
+
* The content of the response.
|
|
19
|
+
*/
|
|
20
|
+
content?: Content;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Indicates whether the text content is part of a unfinished text stream.
|
|
24
|
+
* Only used for streaming mode and when the content is plain text.
|
|
25
|
+
*/
|
|
26
|
+
partial?: boolean;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Indicates whether the response from the model is complete.
|
|
30
|
+
* Only used for streaming mode.
|
|
31
|
+
*/
|
|
32
|
+
turnComplete?: boolean;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Error code if the response is an error. Code varies by model.
|
|
36
|
+
*/
|
|
37
|
+
errorCode?: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Error message if the response is an error.
|
|
41
|
+
*/
|
|
42
|
+
errorMessage?: string;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Flag indicating that LLM was interrupted when generating the content.
|
|
46
|
+
* Usually it's due to user interruption during a bidi streaming.
|
|
47
|
+
*/
|
|
48
|
+
interrupted?: boolean;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The custom metadata of the LlmResponse.
|
|
52
|
+
* An optional key-value pair to label an LlmResponse.
|
|
53
|
+
* NOTE: the entire object must be JSON serializable.
|
|
54
|
+
*/
|
|
55
|
+
customMetadata?: { [key: string]: unknown };
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The finish reason of the response.
|
|
59
|
+
*/
|
|
60
|
+
finishReason?: FinishReason;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The usage metadata of the LlmResponse.
|
|
64
|
+
*/
|
|
65
|
+
usageMetadata?: UsageMetadata;
|
|
66
|
+
}
|