@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.
Files changed (247) hide show
  1. package/dist/agent/agent.d.ts +17 -0
  2. package/dist/agent/agent.js +6 -0
  3. package/dist/agent/agent.js.map +1 -0
  4. package/dist/agent/agent_event.d.ts +108 -0
  5. package/dist/agent/agent_event.js +56 -0
  6. package/dist/agent/agent_event.js.map +1 -0
  7. package/dist/agent/agent_event_utils.d.ts +5 -0
  8. package/dist/agent/agent_event_utils.js +66 -0
  9. package/dist/agent/agent_event_utils.js.map +1 -0
  10. package/dist/agent/cli_agent/cli_agent.d.ts +41 -0
  11. package/dist/agent/cli_agent/cli_agent.js +324 -0
  12. package/dist/agent/cli_agent/cli_agent.js.map +1 -0
  13. package/dist/agent/cli_agent/system_prompt.d.ts +1 -0
  14. package/dist/agent/cli_agent/system_prompt.js +58 -0
  15. package/dist/agent/cli_agent/system_prompt.js.map +1 -0
  16. package/dist/agent/cli_agent.d.ts +34 -0
  17. package/dist/agent/cli_agent.js +91 -0
  18. package/dist/agent/cli_agent.js.map +1 -0
  19. package/dist/agent/planner_agent/planner_agent.d.ts +28 -0
  20. package/dist/agent/planner_agent/planner_agent.js +102 -0
  21. package/dist/agent/planner_agent/planner_agent.js.map +1 -0
  22. package/dist/agent/request_processor/basic_request_processor.d.ts +17 -0
  23. package/dist/agent/request_processor/basic_request_processor.js +28 -0
  24. package/dist/agent/request_processor/basic_request_processor.js.map +1 -0
  25. package/dist/agent/request_processor/compaction_processor.d.ts +17 -0
  26. package/dist/agent/request_processor/compaction_processor.js +118 -0
  27. package/dist/agent/request_processor/compaction_processor.js.map +1 -0
  28. package/dist/agent/request_processor/request_processor.d.ts +11 -0
  29. package/dist/agent/request_processor/request_processor.js +2 -0
  30. package/dist/agent/request_processor/request_processor.js.map +1 -0
  31. package/dist/cli/init_project_command_handler.d.ts +3 -0
  32. package/dist/cli/init_project_command_handler.js +58 -0
  33. package/dist/cli/init_project_command_handler.js.map +1 -0
  34. package/dist/cli/loader.d.ts +6 -0
  35. package/dist/cli/loader.js +27 -0
  36. package/dist/cli/loader.js.map +1 -0
  37. package/dist/cli/prompt_utils.d.ts +11 -0
  38. package/dist/cli/prompt_utils.js +18 -0
  39. package/dist/cli/prompt_utils.js.map +1 -0
  40. package/dist/cli/run_command.d.ts +6 -0
  41. package/dist/cli/run_command.js +72 -0
  42. package/dist/cli/run_command.js.map +1 -0
  43. package/dist/cli/run_interactive_command.d.ts +6 -0
  44. package/dist/cli/run_interactive_command.js +282 -0
  45. package/dist/cli/run_interactive_command.js.map +1 -0
  46. package/dist/cli/run_noninteractive_command.d.ts +6 -0
  47. package/dist/cli/run_noninteractive_command.js +60 -0
  48. package/dist/cli/run_noninteractive_command.js.map +1 -0
  49. package/dist/cli_entrypoint.d.ts +2 -0
  50. package/dist/cli_entrypoint.js +110 -0
  51. package/dist/cli_entrypoint.js.map +1 -0
  52. package/dist/command/commnad_handler.d.ts +3 -0
  53. package/dist/command/commnad_handler.js +2 -0
  54. package/dist/command/commnad_handler.js.map +1 -0
  55. package/dist/command/init_project_command_handler.d.ts +4 -0
  56. package/dist/command/init_project_command_handler.js +58 -0
  57. package/dist/command/init_project_command_handler.js.map +1 -0
  58. package/dist/config/app_dir.d.ts +1 -0
  59. package/dist/config/app_dir.js +4 -0
  60. package/dist/config/app_dir.js.map +1 -0
  61. package/dist/config/config.d.ts +21 -0
  62. package/dist/config/config.js +2 -0
  63. package/dist/config/config.js.map +1 -0
  64. package/dist/config/config_loader.d.ts +2 -0
  65. package/dist/config/config_loader.js +47 -0
  66. package/dist/config/config_loader.js.map +1 -0
  67. package/dist/config/config_store.d.ts +10 -0
  68. package/dist/config/config_store.js +44 -0
  69. package/dist/config/config_store.js.map +1 -0
  70. package/dist/content.d.ts +51 -0
  71. package/dist/content.js +16 -0
  72. package/dist/content.js.map +1 -0
  73. package/dist/core/functions.d.ts +1 -0
  74. package/dist/core/functions.js +6 -0
  75. package/dist/core/functions.js.map +1 -0
  76. package/dist/core/loop.d.ts +20 -0
  77. package/dist/core/loop.js +121 -0
  78. package/dist/core/loop.js.map +1 -0
  79. package/dist/core/project_service.d.ts +11 -0
  80. package/dist/core/project_service.js +26 -0
  81. package/dist/core/project_service.js.map +1 -0
  82. package/dist/core/run.d.ts +6 -0
  83. package/dist/core/run.js +25 -0
  84. package/dist/core/run.js.map +1 -0
  85. package/dist/index.d.ts +1 -0
  86. package/dist/index.js +2 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/logger.d.ts +27 -0
  89. package/dist/logger.js +98 -0
  90. package/dist/logger.js.map +1 -0
  91. package/dist/model/adaptive_model.d.ts +16 -0
  92. package/dist/model/adaptive_model.js +57 -0
  93. package/dist/model/adaptive_model.js.map +1 -0
  94. package/dist/model/google/gemini_model.d.ts +15 -0
  95. package/dist/model/google/gemini_model.js +131 -0
  96. package/dist/model/google/gemini_model.js.map +1 -0
  97. package/dist/model/google/gemini_response_utils.d.ts +3 -0
  98. package/dist/model/google/gemini_response_utils.js +36 -0
  99. package/dist/model/google/gemini_response_utils.js.map +1 -0
  100. package/dist/model/google/gemini_streaming_utils.d.ts +28 -0
  101. package/dist/model/google/gemini_streaming_utils.js +235 -0
  102. package/dist/model/google/gemini_streaming_utils.js.map +1 -0
  103. package/dist/model/google/gen_ai_convert_utils.d.ts +6 -0
  104. package/dist/model/google/gen_ai_convert_utils.js +117 -0
  105. package/dist/model/google/gen_ai_convert_utils.js.map +1 -0
  106. package/dist/model/model.d.ts +11 -0
  107. package/dist/model/model.js +2 -0
  108. package/dist/model/model.js.map +1 -0
  109. package/dist/model/registry.d.ts +19 -0
  110. package/dist/model/registry.js +47 -0
  111. package/dist/model/registry.js.map +1 -0
  112. package/dist/model/request.d.ts +13 -0
  113. package/dist/model/request.js +2 -0
  114. package/dist/model/request.js.map +1 -0
  115. package/dist/model/request_builder_utils.d.ts +19 -0
  116. package/dist/model/request_builder_utils.js +43 -0
  117. package/dist/model/request_builder_utils.js.map +1 -0
  118. package/dist/model/response.d.ts +60 -0
  119. package/dist/model/response.js +2 -0
  120. package/dist/model/response.js.map +1 -0
  121. package/dist/model/util_llm.d.ts +10 -0
  122. package/dist/model/util_llm.js +149 -0
  123. package/dist/model/util_llm.js.map +1 -0
  124. package/dist/session/session.d.ts +14 -0
  125. package/dist/session/session.js +2 -0
  126. package/dist/session/session.js.map +1 -0
  127. package/dist/session/session_file_service.d.ts +23 -0
  128. package/dist/session/session_file_service.js +147 -0
  129. package/dist/session/session_file_service.js.map +1 -0
  130. package/dist/skills/skill.d.ts +23 -0
  131. package/dist/skills/skill.js +12 -0
  132. package/dist/skills/skill.js.map +1 -0
  133. package/dist/tools/build_in/find.d.ts +3 -0
  134. package/dist/tools/build_in/find.js +71 -0
  135. package/dist/tools/build_in/find.js.map +1 -0
  136. package/dist/tools/build_in/grep.d.ts +3 -0
  137. package/dist/tools/build_in/grep.js +97 -0
  138. package/dist/tools/build_in/grep.js.map +1 -0
  139. package/dist/tools/build_in/index.d.ts +1 -0
  140. package/dist/tools/build_in/index.js +13 -0
  141. package/dist/tools/build_in/index.js.map +1 -0
  142. package/dist/tools/build_in/list_dir.d.ts +3 -0
  143. package/dist/tools/build_in/list_dir.js +46 -0
  144. package/dist/tools/build_in/list_dir.js.map +1 -0
  145. package/dist/tools/build_in/view_file.d.ts +3 -0
  146. package/dist/tools/build_in/view_file.js +44 -0
  147. package/dist/tools/build_in/view_file.js.map +1 -0
  148. package/dist/tools/build_in/write_file.d.ts +3 -0
  149. package/dist/tools/build_in/write_file.js +50 -0
  150. package/dist/tools/build_in/write_file.js.map +1 -0
  151. package/dist/tools/functional_tool.d.ts +18 -0
  152. package/dist/tools/functional_tool.js +20 -0
  153. package/dist/tools/functional_tool.js.map +1 -0
  154. package/dist/tools/schema.d.ts +86 -0
  155. package/dist/tools/schema.js +37 -0
  156. package/dist/tools/schema.js.map +1 -0
  157. package/dist/tools/tool.d.ts +30 -0
  158. package/dist/tools/tool.js +9 -0
  159. package/dist/tools/tool.js.map +1 -0
  160. package/dist/tools/tool_call_policy.d.ts +4 -0
  161. package/dist/tools/tool_call_policy.js +4 -0
  162. package/dist/tools/tool_call_policy.js.map +1 -0
  163. package/dist/tools/tool_policy.d.ts +4 -0
  164. package/dist/tools/tool_policy.js +4 -0
  165. package/dist/tools/tool_policy.js.map +1 -0
  166. package/dist/ui/ui.d.ts +1 -0
  167. package/dist/ui/ui.js +2 -0
  168. package/dist/ui/ui.js.map +1 -0
  169. package/dist/user_input.d.ts +20 -0
  170. package/dist/user_input.js +21 -0
  171. package/dist/user_input.js.map +1 -0
  172. package/package.json +44 -0
  173. package/src/agent/agent.ts +18 -0
  174. package/src/agent/agent_event.ts +171 -0
  175. package/src/agent/agent_event_utils.ts +87 -0
  176. package/src/agent/cli_agent/cli_agent.ts +418 -0
  177. package/src/agent/cli_agent/system_prompt.ts +57 -0
  178. package/src/agent/planner_agent/planner_agent.ts +136 -0
  179. package/src/agent/request_processor/basic_request_processor.ts +46 -0
  180. package/src/agent/request_processor/compaction_processor.ts +164 -0
  181. package/src/agent/request_processor/request_processor.ts +13 -0
  182. package/src/cli/loader.ts +27 -0
  183. package/src/cli/prompt_utils.ts +19 -0
  184. package/src/cli/run_interactive_command.ts +337 -0
  185. package/src/cli/run_noninteractive_command.ts +74 -0
  186. package/src/cli_entrypoint.ts +128 -0
  187. package/src/command/commnad_handler.ts +3 -0
  188. package/src/command/init_project_command_handler.ts +66 -0
  189. package/src/config/app_dir.ts +4 -0
  190. package/src/config/config.ts +24 -0
  191. package/src/config/config_loader.ts +57 -0
  192. package/src/config/config_store.ts +50 -0
  193. package/src/content.ts +87 -0
  194. package/src/core/functions.ts +7 -0
  195. package/src/core/loop.ts +165 -0
  196. package/src/core/project_service.ts +38 -0
  197. package/src/core/run.ts +36 -0
  198. package/src/index.ts +1 -0
  199. package/src/logger.ts +128 -0
  200. package/src/model/adaptive_model.ts +77 -0
  201. package/src/model/google/gemini_model.ts +194 -0
  202. package/src/model/google/gemini_response_utils.ts +46 -0
  203. package/src/model/google/gemini_streaming_utils.ts +294 -0
  204. package/src/model/google/gen_ai_convert_utils.ts +149 -0
  205. package/src/model/model.ts +18 -0
  206. package/src/model/registry.ts +61 -0
  207. package/src/model/request.ts +15 -0
  208. package/src/model/request_builder_utils.ts +79 -0
  209. package/src/model/response.ts +66 -0
  210. package/src/model/util_llm.ts +167 -0
  211. package/src/session/session.ts +16 -0
  212. package/src/session/session_file_service.ts +207 -0
  213. package/src/skills/skill.ts +38 -0
  214. package/src/tools/build_in/find.ts +80 -0
  215. package/src/tools/build_in/grep.ts +101 -0
  216. package/src/tools/build_in/index.ts +13 -0
  217. package/src/tools/build_in/list_dir.ts +50 -0
  218. package/src/tools/build_in/view_file.ts +47 -0
  219. package/src/tools/build_in/write_file.ts +53 -0
  220. package/src/tools/functional_tool.ts +59 -0
  221. package/src/tools/schema.ts +87 -0
  222. package/src/tools/tool.ts +68 -0
  223. package/src/tools/tool_call_policy.ts +7 -0
  224. package/src/ui/ui.ts +0 -0
  225. package/src/user_input.ts +51 -0
  226. package/tests/integration/util_llm_test.ts +42 -0
  227. package/tests/unit/adaptive_model_test.ts +122 -0
  228. package/tests/unit/agent/request_processor/compaction_processor_test.ts +121 -0
  229. package/tests/unit/cli/prompt_utils_test.ts +47 -0
  230. package/tests/unit/cli_agent_test.ts +476 -0
  231. package/tests/unit/content_test.ts +56 -0
  232. package/tests/unit/logger_test.ts +109 -0
  233. package/tests/unit/loop_test.ts +141 -0
  234. package/tests/unit/model/gemini_model_test.ts +111 -0
  235. package/tests/unit/planner_agent_test.ts +52 -0
  236. package/tests/unit/project_service_test.ts +102 -0
  237. package/tests/unit/session_file_service_test.ts +160 -0
  238. package/tests/unit/tools/find_test.ts +40 -0
  239. package/tests/unit/tools/grep_test.ts +43 -0
  240. package/tests/unit/tools/list_dir_test.ts +32 -0
  241. package/tests/unit/tools/view_file_test.ts +32 -0
  242. package/tests/unit/tools/write_file_test.ts +44 -0
  243. package/tests/unit/user_input_test.ts +55 -0
  244. package/tests/unit/util_llm_test.ts +61 -0
  245. package/todo.md +29 -0
  246. package/tsconfig.json +33 -0
  247. package/vitest.config.ts +33 -0
package/src/logger.ts ADDED
@@ -0,0 +1,128 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import * as util from "util";
4
+
5
+ export interface LogTransport {
6
+ enabled: boolean;
7
+ log(level: string, formattedMessage: string, args: any[]): void;
8
+ }
9
+
10
+ export class ConsoleTransport implements LogTransport {
11
+ enabled: boolean;
12
+
13
+ constructor(enabled: boolean) {
14
+ this.enabled = enabled;
15
+ }
16
+
17
+ log(level: string, formattedMessage: string, args: any[]) {
18
+ if (!this.enabled) {
19
+ return;
20
+ }
21
+
22
+ switch (level) {
23
+ case "DEBUG":
24
+ console.debug(...args);
25
+ break;
26
+ case "INFO":
27
+ console.info(...args);
28
+ break;
29
+ case "WARN":
30
+ console.warn(...args);
31
+ break;
32
+ case "ERROR":
33
+ console.error(...args);
34
+ break;
35
+ case "LOG":
36
+ default:
37
+ console.log(...args);
38
+ }
39
+ }
40
+ }
41
+
42
+ export class FileTransport implements LogTransport {
43
+ enabled: boolean = true;
44
+
45
+ constructor(
46
+ enabled: boolean,
47
+ private logFile: string,
48
+ ) {
49
+ this.enabled = enabled;
50
+ }
51
+
52
+ log(level: string, formattedMessage: string, args: any[]) {
53
+ if (!this.enabled) {
54
+ return;
55
+ }
56
+
57
+ try {
58
+ fs.appendFileSync(this.logFile, `[${level}] ${formattedMessage}\n`);
59
+ } catch (err) {
60
+ console.error("Failed to write to log file:", err);
61
+ }
62
+ }
63
+ }
64
+
65
+ export class Logger {
66
+ private transports: LogTransport[] = [];
67
+
68
+ constructor(transports?: LogTransport[]) {
69
+ if (transports) {
70
+ this.transports = transports;
71
+ }
72
+ }
73
+
74
+
75
+ getTransports(): LogTransport[] {
76
+ if (this.transports.length) {
77
+ return this.transports;
78
+ }
79
+
80
+ if (process.env.DEBUG_LOGGER) {
81
+ const logFile = path.join(process.cwd(), "debug.log");
82
+
83
+ return [
84
+ new ConsoleTransport(process.env.DEBUG_LOGGER_CONSOLE === "true"),
85
+ new FileTransport(process.env.DEBUG_LOGGER === "true", logFile),
86
+ ];
87
+ }
88
+
89
+ return [];
90
+ }
91
+
92
+ private formatMessage(level: string, ...args: any[]): string {
93
+ const timestamp = new Date().toISOString();
94
+ const message = args
95
+ .map((arg) =>
96
+ typeof arg === "string" ? arg : util.inspect(arg, { depth: null }),
97
+ )
98
+ .join(" ");
99
+ return `[${timestamp}] [${level}] ${message}`;
100
+ }
101
+
102
+ log(...args: any[]) {
103
+ const formatted = this.formatMessage("LOG", ...args);
104
+ this.getTransports().forEach((t) => t.log("LOG", formatted, args));
105
+ }
106
+
107
+ debug(...args: any[]) {
108
+ const formatted = this.formatMessage("DEBUG", ...args);
109
+ this.getTransports().forEach((t) => t.log("DEBUG", formatted, args));
110
+ }
111
+
112
+ info(...args: any[]) {
113
+ const formatted = this.formatMessage("INFO", ...args);
114
+ this.getTransports().forEach((t) => t.log("INFO", formatted, args));
115
+ }
116
+
117
+ warn(...args: any[]) {
118
+ const formatted = this.formatMessage("WARN", ...args);
119
+ this.getTransports().forEach((t) => t.log("WARN", formatted, args));
120
+ }
121
+
122
+ error(...args: any[]) {
123
+ const formatted = this.formatMessage("ERROR", ...args);
124
+ this.getTransports().forEach((t) => t.log("ERROR", formatted, args));
125
+ }
126
+ }
127
+
128
+ export const logger = new Logger();
@@ -0,0 +1,77 @@
1
+ import type { LlmModel, LlmModelConfig } from "./model.js";
2
+ import type { LlmRequest } from "./request.js";
3
+ import type { LlmResponse } from "./response.js";
4
+ import type { ModelConfig } from "../config/config.js";
5
+ import { resolveLlmModel } from "./registry.js";
6
+ import { logger } from "../logger.js";
7
+
8
+ export class AdaptiveLlmModel implements LlmModel {
9
+ private currentModel!: LlmModel;
10
+ private fallbackConfigs?: ModelConfig[];
11
+ readonly modelName: string = "adaptive";
12
+
13
+ constructor(config: { main: ModelConfig; fallback?: ModelConfig[] }) {
14
+ this.setModel(config.main);
15
+ this.fallbackConfigs = config.fallback;
16
+ }
17
+
18
+ setModel(modelConfig: ModelConfig) {
19
+ const ModelClass = resolveLlmModel(modelConfig.modelName);
20
+ this.currentModel = new ModelClass(modelConfig);
21
+ }
22
+
23
+ async *run(
24
+ request: LlmRequest,
25
+ config?: LlmModelConfig,
26
+ ): AsyncGenerator<LlmResponse, void, unknown> {
27
+ if (!this.currentModel) {
28
+ throw new Error("Model not initialized");
29
+ }
30
+
31
+ try {
32
+ yield* this.currentModel.run(request, config);
33
+ } catch (e: unknown) {
34
+ logger.error("[AdaptiveLlmModel] error:", e);
35
+
36
+ if (this.fallbackConfigs && this.fallbackConfigs.length > 0) {
37
+ for (const fallbackConfig of this.fallbackConfigs) {
38
+ logger.info(
39
+ `[AdaptiveLlmModel] Attempting fallback to ${fallbackConfig.modelName}`,
40
+ );
41
+ try {
42
+ const FallbackModelClass = resolveLlmModel(
43
+ fallbackConfig.modelName,
44
+ );
45
+
46
+ this.currentModel = new FallbackModelClass(fallbackConfig);
47
+ yield* this.currentModel.run(request, config);
48
+ return; // Success, exit the generator
49
+ } catch (fallbackError: unknown) {
50
+ logger.error(
51
+ `[AdaptiveLlmModel] fallback to ${fallbackConfig.modelName} failed:`,
52
+ fallbackError,
53
+ );
54
+ // Continue loop to try next fallback
55
+ }
56
+ }
57
+ // If all fallbacks failed
58
+ yield {
59
+ errorCode: "ADAPTIVE_MODEL_ALL_FALLBACKS_FAILED",
60
+ errorMessage: "All fallback models failed.",
61
+ };
62
+ } else {
63
+ yield {
64
+ errorCode: "ADAPTIVE_MODEL_ERROR",
65
+ errorMessage: e instanceof Error ? e.message : String(e),
66
+ };
67
+ }
68
+ }
69
+ }
70
+
71
+ async countTokens(request: LlmRequest): Promise<number> {
72
+ if (!this.currentModel) {
73
+ throw new Error("Model not initialized");
74
+ }
75
+ return this.currentModel.countTokens(request);
76
+ }
77
+ }
@@ -0,0 +1,194 @@
1
+ import {
2
+ GoogleGenAI,
3
+ type GenerateContentParameters,
4
+ ThinkingLevel,
5
+ } from "@google/genai";
6
+ import type { LlmRequest } from "../request.js";
7
+ import type { LlmResponse } from "../response.js";
8
+ import type { ModelConfig } from "../../config/config.js";
9
+ import { contentToGenAIContent } from "./gen_ai_convert_utils.js";
10
+ import { StreamingResponseAggregator } from "./gemini_streaming_utils.js";
11
+ import { createLlmResponse } from "./gemini_response_utils.js";
12
+ import { logger } from "../../logger.js";
13
+
14
+ export interface RunConfig {
15
+ stream?: boolean;
16
+ abortSignal?: AbortSignal;
17
+ }
18
+
19
+ export class Gemini {
20
+ public readonly modelName: string;
21
+ private readonly client: GoogleGenAI;
22
+
23
+ constructor(config: ModelConfig) {
24
+ this.modelName = config.modelName;
25
+ this.client = new GoogleGenAI(config);
26
+ }
27
+
28
+ async *run(
29
+ request: LlmRequest,
30
+ config?: RunConfig,
31
+ ): AsyncGenerator<LlmResponse, void, unknown> {
32
+ logger.debug(
33
+ "[Gemini Model] Running model with request:",
34
+ JSON.stringify(request, null, 2),
35
+ );
36
+
37
+ if (config?.stream) {
38
+ yield* this.runStream(request, config);
39
+ return;
40
+ }
41
+
42
+ try {
43
+ const response = await this.client.models.generateContent(
44
+ toGenAiRequest({
45
+ model: this.modelName,
46
+ request,
47
+ config,
48
+ }),
49
+ );
50
+
51
+ logger.debug(
52
+ "[Gemini Model] response received:",
53
+ JSON.stringify(response, null, 2),
54
+ );
55
+
56
+ yield createLlmResponse(response);
57
+ } catch (e: unknown) {
58
+ logger.error("[Gemini Model] error:", e);
59
+ yield {
60
+ errorCode: "GEMINI_ERROR",
61
+ errorMessage: extractErrorMessage(e),
62
+ };
63
+ }
64
+ }
65
+
66
+ async countTokens(request: LlmRequest): Promise<number> {
67
+ const response = await this.client.models.countTokens({
68
+ model: this.modelName,
69
+ contents: request.contents.map((c) => contentToGenAIContent(c)),
70
+ config: {
71
+ tools: request.tools
72
+ ? [{ functionDeclarations: request.tools }]
73
+ : undefined,
74
+ systemInstruction: request.systemInstructions,
75
+ },
76
+ });
77
+
78
+ logger.debug("[Gemini Model] token count:", response.totalTokens);
79
+
80
+ return response.totalTokens || 0;
81
+ }
82
+
83
+ private async *runStream(
84
+ request: LlmRequest,
85
+ config?: RunConfig,
86
+ ): AsyncGenerator<LlmResponse, void, unknown> {
87
+ try {
88
+ const aggregator = new StreamingResponseAggregator();
89
+ const stream = await this.client.models.generateContentStream(
90
+ toGenAiRequest({
91
+ model: this.modelName,
92
+ request,
93
+ config,
94
+ }),
95
+ );
96
+
97
+ for await (const response of stream) {
98
+ for await (const llmResponse of aggregator.processResponse(response)) {
99
+ logger.debug(
100
+ "[Gemini Model] yielding streaming response",
101
+ JSON.stringify(llmResponse, null, 2),
102
+ );
103
+
104
+ yield llmResponse;
105
+ }
106
+ }
107
+
108
+ const finalResponse = aggregator.close();
109
+ if (finalResponse) {
110
+ logger.debug(
111
+ "[Gemini Model] yielding final streaming response",
112
+ JSON.stringify(finalResponse, null, 2),
113
+ );
114
+
115
+ yield finalResponse;
116
+ }
117
+ } catch (e: unknown) {
118
+ logger.error("[Gemini Model] stream error:", e);
119
+ yield {
120
+ errorCode: "GEMINI_STREAM_ERROR",
121
+ errorMessage: extractErrorMessage(e),
122
+ };
123
+ }
124
+
125
+ logger.debug("[Gemini Model] stream finished");
126
+ }
127
+ }
128
+
129
+ interface ToGenAiRequestConfig {
130
+ model: string;
131
+ request: LlmRequest;
132
+ config?: RunConfig;
133
+ }
134
+ function toGenAiRequest({
135
+ model,
136
+ request,
137
+ config = {},
138
+ }: ToGenAiRequestConfig): GenerateContentParameters {
139
+ return {
140
+ model,
141
+ contents: request.contents.map((c) => contentToGenAIContent(c)),
142
+ config: {
143
+ ...(config || {}),
144
+ tools: request.tools
145
+ ? [{ functionDeclarations: request.tools }]
146
+ : undefined,
147
+ thinkingConfig: request.thinkingConfig?.enabled ? {
148
+ includeThoughts: request.thinkingConfig.enabled,
149
+ thinkingLevel: toThinkingLevelConfig(
150
+ request.thinkingConfig.level || "auto",
151
+ ),
152
+ } : undefined,
153
+ systemInstruction: request.systemInstructions,
154
+ },
155
+ };
156
+ }
157
+
158
+ function extractErrorMessage(e: unknown): string {
159
+ if (e instanceof Error) {
160
+ try {
161
+ const parsed = JSON.parse(e.message);
162
+ if (parsed.error && parsed.error.message) {
163
+ try {
164
+ const innerParsed = JSON.parse(parsed.error.message);
165
+ if (innerParsed.error && innerParsed.error.message) {
166
+ return innerParsed.error.message;
167
+ }
168
+ } catch {
169
+ return parsed.error.message;
170
+ }
171
+ return parsed.error.message;
172
+ }
173
+ } catch {
174
+ return e.message;
175
+ }
176
+ return e.message;
177
+ }
178
+ return String(e);
179
+ }
180
+
181
+ function toThinkingLevelConfig(
182
+ thinkingLevel: "low" | "medium" | "high" | "auto",
183
+ ): ThinkingLevel {
184
+ switch (thinkingLevel) {
185
+ case "low":
186
+ return ThinkingLevel.LOW;
187
+ case "medium":
188
+ return ThinkingLevel.MEDIUM;
189
+ case "high":
190
+ return ThinkingLevel.HIGH;
191
+ case "auto":
192
+ return ThinkingLevel.HIGH;
193
+ }
194
+ }
@@ -0,0 +1,46 @@
1
+ import { GenerateContentResponse, FinishReason } from "@google/genai";
2
+ import type { LlmResponse } from "../response.js";
3
+ import { genAIContentToContent } from "./gen_ai_convert_utils.js";
4
+
5
+ export function createLlmResponse(
6
+ response: GenerateContentResponse,
7
+ ): LlmResponse {
8
+ const candidate = response.candidates?.[0];
9
+
10
+ const llmResponse: LlmResponse = {};
11
+
12
+ if (response.usageMetadata) {
13
+ llmResponse.usageMetadata = {
14
+ inputTokens: response.usageMetadata.promptTokenCount,
15
+ outputTokens: response.usageMetadata.candidatesTokenCount,
16
+ cachedTokens: response.usageMetadata.cachedContentTokenCount,
17
+ };
18
+ }
19
+
20
+ if (candidate) {
21
+ if (candidate.content) {
22
+ llmResponse.content = genAIContentToContent(candidate.content);
23
+ }
24
+
25
+ if (candidate.finishReason) {
26
+ llmResponse.finishReason = candidate.finishReason;
27
+
28
+ if (candidate.finishReason !== FinishReason.STOP) {
29
+ llmResponse.errorCode = candidate.finishReason;
30
+ llmResponse.errorMessage = (candidate as any).finishMessage;
31
+ }
32
+ }
33
+ }
34
+
35
+ if (candidate) {
36
+ const cand = candidate as any;
37
+ if (cand.groundingMetadata) {
38
+ (llmResponse as any).groundingMetadata = cand.groundingMetadata;
39
+ }
40
+ if (cand.citationMetadata) {
41
+ (llmResponse as any).citationMetadata = cand.citationMetadata;
42
+ }
43
+ }
44
+
45
+ return llmResponse;
46
+ }