@kkeve/suite 0.0.1 → 0.0.2

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 (152) hide show
  1. package/README.md +53 -0
  2. package/dist/bin/keve.d.ts +13 -0
  3. package/dist/bin/keve.js +164 -0
  4. package/dist/commands/auth-update.d.ts +16 -0
  5. package/dist/commands/auth-update.js +88 -0
  6. package/dist/commands/clean.d.ts +10 -0
  7. package/dist/commands/clean.js +78 -0
  8. package/dist/commands/config.d.ts +17 -0
  9. package/dist/commands/config.js +99 -0
  10. package/dist/commands/init.d.ts +15 -0
  11. package/dist/commands/init.js +292 -0
  12. package/dist/commands/report.d.ts +12 -0
  13. package/dist/commands/report.js +159 -0
  14. package/dist/commands/run.d.ts +29 -0
  15. package/dist/commands/run.js +417 -0
  16. package/dist/commands/test.d.ts +12 -0
  17. package/dist/commands/test.js +102 -0
  18. package/dist/commands/vitest.d.ts +14 -0
  19. package/dist/commands/vitest.js +166 -0
  20. package/dist/config.d.ts +109 -0
  21. package/dist/config.js +291 -0
  22. package/dist/core/action-log-writer.d.ts +47 -0
  23. package/dist/{tools/write-file.js → core/action-log-writer.js} +42 -26
  24. package/dist/core/auth.d.ts +17 -0
  25. package/dist/core/auth.js +224 -0
  26. package/dist/core/cdp-resolver.d.ts +5 -0
  27. package/dist/core/cdp-resolver.js +93 -0
  28. package/dist/core/generateReport/report.d.ts +19 -0
  29. package/dist/core/generateReport/report.js +91 -0
  30. package/dist/core/generateReport/reportData.d.ts +215 -0
  31. package/dist/core/generateReport/reportData.js +735 -0
  32. package/dist/core/global-setup.d.ts +6 -0
  33. package/dist/core/global-setup.js +113 -0
  34. package/dist/core/keve-aspect.d.ts +54 -0
  35. package/dist/core/keve-aspect.js +52 -0
  36. package/dist/core/keve-decorators.d.ts +51 -0
  37. package/dist/core/keve-decorators.js +95 -0
  38. package/dist/core/keve-registry.d.ts +38 -0
  39. package/dist/core/keve-registry.js +25 -0
  40. package/dist/core/keve-report.d.ts +27 -0
  41. package/dist/core/keve-report.js +357 -0
  42. package/dist/core/keve-test.d.ts +36 -0
  43. package/dist/core/keve-test.js +364 -0
  44. package/dist/core/learned-actions.d.ts +24 -0
  45. package/dist/core/learned-actions.js +65 -0
  46. package/dist/core/pw-config.d.ts +19 -0
  47. package/dist/core/pw-config.js +180 -0
  48. package/dist/index.d.ts +8 -23
  49. package/dist/index.js +36 -43
  50. package/dist/page-agent/agent.d.ts +129 -0
  51. package/dist/page-agent/agent.js +585 -0
  52. package/dist/page-agent/hooks.d.ts +13 -0
  53. package/dist/page-agent/hooks.js +218 -0
  54. package/dist/page-agent/tools.d.ts +29 -0
  55. package/dist/page-agent/tools.js +297 -0
  56. package/doc/README.md +124 -0
  57. package/doc/agents/keve-dev-test-agent.md +140 -0
  58. package/doc/agents/keve-test-agent.md +178 -0
  59. package/doc/asserts//346/265/213/350/257/225/345/220/204/351/230/266/346/256/265/350/257/264/346/230/216.png +0 -0
  60. package/doc/keve-agent-demo.html +370 -0
  61. package/doc/skills/keve-bddcase-gen/SKILL.md +332 -0
  62. package/doc/skills/keve-bddcase-gen/references/test-case-rules.md +91 -0
  63. package/doc/skills/keve-bddcase-gen/references/test-cases-example.md +103 -0
  64. package/doc/skills/keve-component-gen/SKILL.md +255 -0
  65. package/doc/skills/keve-component-gen/references/component-mock-strategy.md +74 -0
  66. package/doc/skills/keve-component-gen/references/component-model-template.md +98 -0
  67. package/doc/skills/keve-component-gen/references/component-test-template.md +100 -0
  68. package/doc/skills/keve-component-gen/references/vue-test-utils-guide.md +91 -0
  69. package/doc/skills/keve-e2e-gen/SKILL.md +179 -0
  70. package/doc/skills/keve-e2e-gen/references/code-analysis-guide.md +208 -0
  71. package/doc/skills/keve-e2e-gen/references/decisions.md +36 -0
  72. package/doc/skills/keve-e2e-gen/references/pom-generation-guide.md +140 -0
  73. package/doc/skills/keve-e2e-gen/references/script-generation-guide.md +236 -0
  74. package/doc/skills/keve-e2e-gen/references/test-auditor-guide.md +189 -0
  75. package/doc/skills/keve-e2e-gen/scripts/extract-components.sh +85 -0
  76. package/doc/skills/keve-e2e-gen/scripts/inject-testids.sh +95 -0
  77. package/doc/skills/keve-static-analysis/SKILL.md +362 -0
  78. package/doc/skills/keve-static-analysis/references/codegraph-analysis-guide.md +108 -0
  79. package/doc/skills/keve-static-analysis/references/git-impact-analysis.md +81 -0
  80. package/doc/skills/keve-static-analysis/references/lint-fix-guide.md +69 -0
  81. package/doc/skills/keve-static-analysis/references/runtime-risk-patterns.md +92 -0
  82. package/doc/skills/keve-static-analysis/references/security-scan-guide.md +32 -0
  83. package/doc/skills/keve-static-analysis/references/ts-error-patterns.md +98 -0
  84. package/doc/skills/keve-static-analysis/references/vue-security-guide.md +72 -0
  85. package/doc/skills/keve-test-eval/SKILL.md +78 -0
  86. package/doc/skills/keve-test-eval/references/common-fix-guide.md +166 -0
  87. package/doc/skills/keve-test-eval/references/confidence-data-guide.md +78 -0
  88. package/doc/skills/keve-test-eval/references/fix-loop-guide.md +67 -0
  89. package/doc/skills/keve-unit-gen/SKILL.md +203 -0
  90. package/doc/skills/keve-unit-gen/references/boundary-conditions.md +78 -0
  91. package/doc/skills/keve-unit-gen/references/unit-mock-strategy.md +71 -0
  92. package/doc/skills/keve-unit-gen/references/unit-test-template.md +105 -0
  93. package/package.json +47 -25
  94. package/dist/agent/factory.d.ts +0 -25
  95. package/dist/agent/factory.js +0 -99
  96. package/dist/agent/index.d.ts +0 -3
  97. package/dist/agent/index.js +0 -7
  98. package/dist/agent/loader.d.ts +0 -22
  99. package/dist/agent/loader.js +0 -117
  100. package/dist/agent/types.d.ts +0 -9
  101. package/dist/agent/types.js +0 -2
  102. package/dist/agent-loop/complete-task.d.ts +0 -28
  103. package/dist/agent-loop/complete-task.js +0 -70
  104. package/dist/agent-loop/index.d.ts +0 -16
  105. package/dist/agent-loop/index.js +0 -26
  106. package/dist/agent-loop/loop.d.ts +0 -42
  107. package/dist/agent-loop/loop.js +0 -282
  108. package/dist/agent-loop/runtime.d.ts +0 -40
  109. package/dist/agent-loop/runtime.js +0 -163
  110. package/dist/agent-loop/types.d.ts +0 -161
  111. package/dist/agent-loop/types.js +0 -105
  112. package/dist/context/index.d.ts +0 -8
  113. package/dist/context/index.js +0 -29
  114. package/dist/context/tokenCalculation.d.ts +0 -55
  115. package/dist/context/tokenCalculation.js +0 -95
  116. package/dist/context/truncation.d.ts +0 -67
  117. package/dist/context/truncation.js +0 -142
  118. package/dist/context/types.d.ts +0 -7
  119. package/dist/context/types.js +0 -27
  120. package/dist/llm/OpenAIClient.d.ts +0 -31
  121. package/dist/llm/OpenAIClient.js +0 -455
  122. package/dist/llm/constants.d.ts +0 -2
  123. package/dist/llm/constants.js +0 -6
  124. package/dist/llm/errors.d.ts +0 -25
  125. package/dist/llm/errors.js +0 -51
  126. package/dist/llm/index.d.ts +0 -49
  127. package/dist/llm/index.js +0 -158
  128. package/dist/llm/types.d.ts +0 -124
  129. package/dist/llm/types.js +0 -2
  130. package/dist/llm/utils.d.ts +0 -29
  131. package/dist/llm/utils.js +0 -284
  132. package/dist/skill/frontmatter-parser.d.ts +0 -50
  133. package/dist/skill/frontmatter-parser.js +0 -152
  134. package/dist/skill/index.d.ts +0 -12
  135. package/dist/skill/index.js +0 -17
  136. package/dist/skill/loader.d.ts +0 -96
  137. package/dist/skill/loader.js +0 -256
  138. package/dist/tools/ask-user.d.ts +0 -8
  139. package/dist/tools/ask-user.js +0 -47
  140. package/dist/tools/bash.d.ts +0 -47
  141. package/dist/tools/bash.js +0 -213
  142. package/dist/tools/edit-file.d.ts +0 -9
  143. package/dist/tools/edit-file.js +0 -76
  144. package/dist/tools/glob.d.ts +0 -8
  145. package/dist/tools/glob.js +0 -101
  146. package/dist/tools/grep.d.ts +0 -10
  147. package/dist/tools/grep.js +0 -76
  148. package/dist/tools/index.d.ts +0 -24
  149. package/dist/tools/index.js +0 -47
  150. package/dist/tools/read-files.d.ts +0 -8
  151. package/dist/tools/read-files.js +0 -81
  152. package/dist/tools/write-file.d.ts +0 -8
@@ -1,7 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AgentFactory = exports.AgentLoader = void 0;
4
- var loader_1 = require("./loader");
5
- Object.defineProperty(exports, "AgentLoader", { enumerable: true, get: function () { return loader_1.AgentLoader; } });
6
- var factory_1 = require("./factory");
7
- Object.defineProperty(exports, "AgentFactory", { enumerable: true, get: function () { return factory_1.AgentFactory; } });
@@ -1,22 +0,0 @@
1
- /**
2
- * AgentLoader — discovers and loads .md agent definitions from a directory
3
- *
4
- * Mirrors SkillLoader pattern (instance-based, no singleton).
5
- * Each .md file uses YAML frontmatter (same as SKILL.md) to define agent metadata.
6
- */
7
- import type { AgentRegistryDefinition } from './types';
8
- export declare class AgentLoader {
9
- private agentsDir;
10
- private agents;
11
- constructor(agentsDir: string);
12
- discover(): Promise<void>;
13
- get(name: string): AgentRegistryDefinition | undefined;
14
- has(name: string): boolean;
15
- getAll(): Map<string, AgentRegistryDefinition>;
16
- listAvailable(): Array<{
17
- name: string;
18
- description: string;
19
- outputType?: string;
20
- }>;
21
- reset(): void;
22
- }
@@ -1,117 +0,0 @@
1
- "use strict";
2
- /**
3
- * AgentLoader — discovers and loads .md agent definitions from a directory
4
- *
5
- * Mirrors SkillLoader pattern (instance-based, no singleton).
6
- * Each .md file uses YAML frontmatter (same as SKILL.md) to define agent metadata.
7
- */
8
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
- if (k2 === undefined) k2 = k;
10
- var desc = Object.getOwnPropertyDescriptor(m, k);
11
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
- desc = { enumerable: true, get: function() { return m[k]; } };
13
- }
14
- Object.defineProperty(o, k2, desc);
15
- }) : (function(o, m, k, k2) {
16
- if (k2 === undefined) k2 = k;
17
- o[k2] = m[k];
18
- }));
19
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
- Object.defineProperty(o, "default", { enumerable: true, value: v });
21
- }) : function(o, v) {
22
- o["default"] = v;
23
- });
24
- var __importStar = (this && this.__importStar) || (function () {
25
- var ownKeys = function(o) {
26
- ownKeys = Object.getOwnPropertyNames || function (o) {
27
- var ar = [];
28
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
- return ar;
30
- };
31
- return ownKeys(o);
32
- };
33
- return function (mod) {
34
- if (mod && mod.__esModule) return mod;
35
- var result = {};
36
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
- __setModuleDefault(result, mod);
38
- return result;
39
- };
40
- })();
41
- Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.AgentLoader = void 0;
43
- const fs = __importStar(require("node:fs/promises"));
44
- const path = __importStar(require("node:path"));
45
- const glob_1 = require("glob");
46
- const frontmatter_parser_1 = require("../skill/frontmatter-parser");
47
- class AgentLoader {
48
- agentsDir;
49
- agents = new Map();
50
- constructor(agentsDir) {
51
- this.agentsDir = agentsDir;
52
- }
53
- async discover() {
54
- const absoluteDir = path.resolve(this.agentsDir);
55
- try {
56
- const stats = await fs.stat(absoluteDir).catch(() => null);
57
- if (!stats || !stats.isDirectory()) {
58
- console.warn(`[AgentLoader] Agents directory not found: ${absoluteDir}`);
59
- return;
60
- }
61
- const agentFiles = await (0, glob_1.glob)('*.md', {
62
- cwd: absoluteDir,
63
- absolute: true,
64
- nodir: true,
65
- });
66
- for (const agentFile of agentFiles) {
67
- try {
68
- const content = await fs.readFile(agentFile, 'utf-8');
69
- const parsed = (0, frontmatter_parser_1.parseSkillFrontmatter)(content);
70
- if (!parsed || !parsed.name) {
71
- console.warn(`[AgentLoader] Invalid agent file: ${agentFile}`);
72
- continue;
73
- }
74
- const tools = parsed.allowedTools ?? [];
75
- const agent = {
76
- name: parsed.name,
77
- description: parsed.description,
78
- tools,
79
- outputType: parsed.outputType,
80
- model: undefined,
81
- prompt: parsed.body,
82
- location: agentFile,
83
- };
84
- this.agents.set(parsed.name, agent);
85
- console.log(`[AgentLoader] Loaded agent: "${parsed.name}" (tools: ${tools.join(', ')}, outputType: ${parsed.outputType ?? 'N/A'})`);
86
- }
87
- catch (err) {
88
- console.warn(`[AgentLoader] Failed to load ${agentFile}: ${err.message}`);
89
- }
90
- }
91
- console.log(`[AgentLoader] Total agents: ${this.agents.size}`);
92
- }
93
- catch (err) {
94
- console.warn(`[AgentLoader] Error discovering agents: ${err.message}`);
95
- }
96
- }
97
- get(name) {
98
- return this.agents.get(name);
99
- }
100
- has(name) {
101
- return this.agents.has(name);
102
- }
103
- getAll() {
104
- return this.agents;
105
- }
106
- listAvailable() {
107
- return Array.from(this.agents.values()).map(a => ({
108
- name: a.name,
109
- description: a.description,
110
- outputType: a.outputType,
111
- }));
112
- }
113
- reset() {
114
- this.agents.clear();
115
- }
116
- }
117
- exports.AgentLoader = AgentLoader;
@@ -1,9 +0,0 @@
1
- export interface AgentRegistryDefinition {
2
- name: string;
3
- description: string;
4
- tools: string[];
5
- outputType?: string;
6
- model?: string;
7
- prompt: string;
8
- location: string;
9
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,28 +0,0 @@
1
- /**
2
- * Complete Task Tool — signals that the agent has finished its task.
3
- *
4
- * Reference: gemini-cli CompleteTaskTool (tools/complete-task.ts)
5
- *
6
- * This tool is automatically registered in every agent loop execution.
7
- * When the LLM calls this tool, the agent loop terminates with GOAL mode.
8
- *
9
- * The `result` parameter can be either:
10
- * - A structured JSON object (when the agent has a defined output schema)
11
- * - A plain string summary (for conversational tasks)
12
- */
13
- import { z } from 'zod/v4';
14
- import type { ToolDefinition } from './types';
15
- export interface CompleteTaskToolOptions {
16
- outputHint?: string;
17
- }
18
- export declare const CompleteTaskSchema: z.ZodObject<{
19
- result: z.ZodAny;
20
- _result: z.ZodOptional<z.ZodEnum<{
21
- PASSED: "PASSED";
22
- FAILED: "FAILED";
23
- BLOCKED: "BLOCKED";
24
- }>>;
25
- _summary: z.ZodOptional<z.ZodString>;
26
- _blockedReason: z.ZodOptional<z.ZodString>;
27
- }, z.core.$strip>;
28
- export declare function createCompleteTaskTool(options?: CompleteTaskToolOptions): ToolDefinition;
@@ -1,70 +0,0 @@
1
- "use strict";
2
- /**
3
- * Complete Task Tool — signals that the agent has finished its task.
4
- *
5
- * Reference: gemini-cli CompleteTaskTool (tools/complete-task.ts)
6
- *
7
- * This tool is automatically registered in every agent loop execution.
8
- * When the LLM calls this tool, the agent loop terminates with GOAL mode.
9
- *
10
- * The `result` parameter can be either:
11
- * - A structured JSON object (when the agent has a defined output schema)
12
- * - A plain string summary (for conversational tasks)
13
- */
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.CompleteTaskSchema = void 0;
16
- exports.createCompleteTaskTool = createCompleteTaskTool;
17
- const v4_1 = require("zod/v4");
18
- const types_1 = require("./types");
19
- exports.CompleteTaskSchema = v4_1.z.object({
20
- result: v4_1.z.any().describe('Your final result. You can provide either a structured JSON object or a text summary. ' +
21
- 'This is the ONLY way to finish the task — call this tool when you are done.'),
22
- _result: v4_1.z.enum(['PASSED', 'FAILED', 'BLOCKED']).optional().describe('Execution result. "PASSED" = task completed successfully. ' +
23
- '"FAILED" = task failed (e.g. tests did not pass). ' +
24
- '"BLOCKED" = unresolved items prevent downstream steps from proceeding safely. ' +
25
- 'Use "BLOCKED" when critical information is missing and proceeding would produce unreliable results.'),
26
- _summary: v4_1.z.string().optional().describe('Brief human-readable summary of the result (1-2 sentences). Used by the orchestrator to display progress. ' +
27
- 'If omitted, the orchestrator will derive a summary from the result object.'),
28
- _blockedReason: v4_1.z.string().optional().describe('Reason for blocking. Required when _result is "BLOCKED". ' +
29
- 'Describe what information is missing and what needs to be confirmed before proceeding.'),
30
- });
31
- function createCompleteTaskTool(options) {
32
- const hint = options?.outputHint;
33
- const baseDescription = 'Call this tool to submit your final result and complete the task. ' +
34
- 'This is the ONLY way to finish. You MUST call this tool when you ' +
35
- 'have completed your work.';
36
- const description = hint
37
- ? baseDescription + '\n\n' + hint
38
- : baseDescription;
39
- const structuredDesc = hint
40
- ? 'Structured JSON result. ' + hint
41
- : 'Structured JSON result with key fields matching the expected output schema.';
42
- return {
43
- name: types_1.COMPLETE_TASK_TOOL_NAME,
44
- description,
45
- inputSchema: exports.CompleteTaskSchema,
46
- execute: async (args) => {
47
- const result = typeof args.result === 'string' ? args.result : args.result;
48
- return { result, taskCompleted: true };
49
- },
50
- customJsonSchema: {
51
- type: 'object',
52
- properties: {
53
- result: {
54
- oneOf: [
55
- {
56
- type: 'object',
57
- description: structuredDesc,
58
- },
59
- {
60
- type: 'string',
61
- description: 'Plain text summary of what you accomplished.',
62
- },
63
- ],
64
- description: 'Your final result. Provide structured JSON when a schema is defined, or a text summary otherwise.',
65
- },
66
- },
67
- required: ['result'],
68
- },
69
- };
70
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Agent Loop module — universal agent execution engine
3
- *
4
- * Provides the core agent loop runtime that executes an AgentDefinition
5
- * by calling the LLM in a while loop, processing tool_calls, and
6
- * terminating when complete_task is called or limits are reached.
7
- *
8
- * Reference: gemini-cli LocalAgentExecutor (agents/local-executor.ts)
9
- */
10
- export { AgentLoop } from './loop';
11
- export { createCompleteTaskTool, CompleteTaskSchema } from './complete-task';
12
- export type { CompleteTaskToolOptions } from './complete-task';
13
- export type { AgentDefinition, AgentEvent, AgentEventCallback, AgentLoopContext, AgentResult, AgentTerminateMode, ToolDefinition, ToolExecutionContext, } from './types';
14
- export { ToolRegistry, COMPLETE_TASK_TOOL_NAME, DEFAULT_MAX_TURNS, DEFAULT_MAX_TIME_MINUTES, } from './types';
15
- export { detectRuntimeEnvironment } from './runtime';
16
- export type { RuntimeEnvironment } from './runtime';
@@ -1,26 +0,0 @@
1
- "use strict";
2
- /**
3
- * Agent Loop module — universal agent execution engine
4
- *
5
- * Provides the core agent loop runtime that executes an AgentDefinition
6
- * by calling the LLM in a while loop, processing tool_calls, and
7
- * terminating when complete_task is called or limits are reached.
8
- *
9
- * Reference: gemini-cli LocalAgentExecutor (agents/local-executor.ts)
10
- */
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.detectRuntimeEnvironment = exports.DEFAULT_MAX_TIME_MINUTES = exports.DEFAULT_MAX_TURNS = exports.COMPLETE_TASK_TOOL_NAME = exports.ToolRegistry = exports.CompleteTaskSchema = exports.createCompleteTaskTool = exports.AgentLoop = void 0;
13
- var loop_1 = require("./loop");
14
- Object.defineProperty(exports, "AgentLoop", { enumerable: true, get: function () { return loop_1.AgentLoop; } });
15
- var complete_task_1 = require("./complete-task");
16
- Object.defineProperty(exports, "createCompleteTaskTool", { enumerable: true, get: function () { return complete_task_1.createCompleteTaskTool; } });
17
- Object.defineProperty(exports, "CompleteTaskSchema", { enumerable: true, get: function () { return complete_task_1.CompleteTaskSchema; } });
18
- var types_1 = require("./types");
19
- Object.defineProperty(exports, "ToolRegistry", { enumerable: true, get: function () { return types_1.ToolRegistry; } });
20
- // Constants
21
- Object.defineProperty(exports, "COMPLETE_TASK_TOOL_NAME", { enumerable: true, get: function () { return types_1.COMPLETE_TASK_TOOL_NAME; } });
22
- Object.defineProperty(exports, "DEFAULT_MAX_TURNS", { enumerable: true, get: function () { return types_1.DEFAULT_MAX_TURNS; } });
23
- Object.defineProperty(exports, "DEFAULT_MAX_TIME_MINUTES", { enumerable: true, get: function () { return types_1.DEFAULT_MAX_TIME_MINUTES; } });
24
- // Runtime Environment
25
- var runtime_1 = require("./runtime");
26
- Object.defineProperty(exports, "detectRuntimeEnvironment", { enumerable: true, get: function () { return runtime_1.detectRuntimeEnvironment; } });
@@ -1,42 +0,0 @@
1
- /**
2
- * Agent Loop — universal agent execution engine
3
- *
4
- * Reference: gemini-cli LocalAgentExecutor (agents/local-executor.ts L120-1518)
5
- * Key adaptation: uses OpenAIClient.chat() instead of GeminiChat,
6
- * decoupled tool execution via ToolRegistry, simplified timeout.
7
- *
8
- * Core loop:
9
- * 1. Build messages (system prompt + user query)
10
- * 2. While (!done):
11
- * a. Check termination (max turns, timeout, abort)
12
- * b. Call LLM via chatWithTools → get assistant message
13
- * c. If no tool_calls → ERROR_NO_COMPLETE_TASK (or handle text-only response)
14
- * d. For each tool_call:
15
- * - If complete_task → done, extract result
16
- * - Otherwise → execute via ToolRegistry → append tool response
17
- * e. Emit events (thought_chunk, tool_call_start/end)
18
- * 3. Return AgentResult with termination mode and output
19
- */
20
- import type { AgentDefinition, AgentEventCallback, AgentResult } from './types';
21
- import { ToolRegistry } from './types';
22
- import type { LLM } from '../llm/index';
23
- export declare class AgentLoop {
24
- private llm;
25
- private toolRegistry;
26
- constructor(llm: LLM, toolRegistry: ToolRegistry);
27
- /**
28
- * Execute an agent definition with the given event callback and optional abort signal.
29
- *
30
- * Reference: gemini-cli LocalAgentExecutor.run() (L537-566) and runInternal() (L568-730)
31
- */
32
- execute(definition: AgentDefinition, onEvent?: AgentEventCallback, signal?: AbortSignal): Promise<AgentResult>;
33
- /**
34
- * Check if the agent should terminate.
35
- * Returns a terminate reason if termination is needed, null otherwise.
36
- */
37
- private checkTermination;
38
- /**
39
- * Emit an event to the callback, if provided.
40
- */
41
- private emitEvent;
42
- }
@@ -1,282 +0,0 @@
1
- "use strict";
2
- /**
3
- * Agent Loop — universal agent execution engine
4
- *
5
- * Reference: gemini-cli LocalAgentExecutor (agents/local-executor.ts L120-1518)
6
- * Key adaptation: uses OpenAIClient.chat() instead of GeminiChat,
7
- * decoupled tool execution via ToolRegistry, simplified timeout.
8
- *
9
- * Core loop:
10
- * 1. Build messages (system prompt + user query)
11
- * 2. While (!done):
12
- * a. Check termination (max turns, timeout, abort)
13
- * b. Call LLM via chatWithTools → get assistant message
14
- * c. If no tool_calls → ERROR_NO_COMPLETE_TASK (or handle text-only response)
15
- * d. For each tool_call:
16
- * - If complete_task → done, extract result
17
- * - Otherwise → execute via ToolRegistry → append tool response
18
- * e. Emit events (thought_chunk, tool_call_start/end)
19
- * 3. Return AgentResult with termination mode and output
20
- */
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.AgentLoop = void 0;
23
- const types_1 = require("./types");
24
- const complete_task_1 = require("./complete-task");
25
- const index_1 = require("../llm/index");
26
- /**
27
- * Universal agent execution engine.
28
- *
29
- * Usage:
30
- * ```typescript
31
- * const loop = new AgentLoop(llm, toolRegistry)
32
- * const result = await loop.execute(
33
- * { name: 'my-agent', systemPrompt: '...', query: 'Do X' },
34
- * (event) => { }
35
- */
36
- const FILE_CONTENT_TRUNCATE = 80;
37
- function truncateFileContent(data, toolName) {
38
- if (!toolName)
39
- return data;
40
- const result = { ...data };
41
- // 截断顶层 content(read_files 返回结果等)
42
- if ((toolName === 'write_file' || toolName === 'edit_file') && typeof data.content === 'string' && data.content.length > FILE_CONTENT_TRUNCATE) {
43
- result.content = data.content.slice(0, FILE_CONTENT_TRUNCATE) + `... (${data.content.length} chars)`;
44
- }
45
- // 截断 args.content(tool_call_start 中 write_file/edit_file 的参数)
46
- if ((toolName === 'write_file' || toolName === 'edit_file') && data.args && typeof data.args.content === 'string' && data.args.content.length > FILE_CONTENT_TRUNCATE) {
47
- result.args = { ...data.args };
48
- result.args.content = data.args.content.slice(0, FILE_CONTENT_TRUNCATE) + `... (${data.args.content.length} chars)`;
49
- }
50
- if (toolName === 'read_files' && typeof data.result === 'string' && data.result.length > FILE_CONTENT_TRUNCATE) {
51
- result.result = data.result.slice(0, FILE_CONTENT_TRUNCATE) + `... (${data.result.length} chars)`;
52
- }
53
- return result;
54
- }
55
- class AgentLoop {
56
- llm;
57
- toolRegistry;
58
- constructor(llm, toolRegistry) {
59
- this.llm = llm;
60
- this.toolRegistry = toolRegistry;
61
- }
62
- /**
63
- * Execute an agent definition with the given event callback and optional abort signal.
64
- *
65
- * Reference: gemini-cli LocalAgentExecutor.run() (L537-566) and runInternal() (L568-730)
66
- */
67
- async execute(definition, onEvent, signal) {
68
- const startTime = Date.now();
69
- const maxTurns = definition.maxTurns ?? types_1.DEFAULT_MAX_TURNS;
70
- const maxTimeMs = (definition.maxTimeMinutes ?? types_1.DEFAULT_MAX_TIME_MINUTES) * 60 * 1000;
71
- let turnCounter = 0;
72
- let terminateReason = types_1.TM_ERROR;
73
- let finalResult = null;
74
- // 1. Build initial messages
75
- const messages = [];
76
- if (definition.systemPrompt) {
77
- messages.push({ role: 'system', content: definition.systemPrompt });
78
- }
79
- const query = definition.query ?? 'Get Started!';
80
- messages.push({ role: 'user', content: query });
81
- // 2. Use a local tool registry copy to avoid mutating the shared one
82
- const localRegistry = new types_1.ToolRegistry();
83
- // Copy all tools from the shared registry
84
- for (const name of this.toolRegistry.getAllToolNames()) {
85
- const tool = this.toolRegistry.get(name);
86
- if (tool)
87
- localRegistry.register(tool);
88
- }
89
- // Ensure complete_task is registered (check if caller already registered one)
90
- if (!localRegistry.has(types_1.COMPLETE_TASK_TOOL_NAME)) {
91
- localRegistry.register((0, complete_task_1.createCompleteTaskTool)());
92
- }
93
- // Determine which tools are available for this agent
94
- const toolsMap = definition.toolNames
95
- ? localRegistry.getToolsMapSubset([...definition.toolNames, types_1.COMPLETE_TASK_TOOL_NAME])
96
- : localRegistry.getToolsMap();
97
- // 3. Emit start event
98
- this.emitEvent(onEvent, 'agent_start', definition.name, {
99
- agentName: definition.name,
100
- maxTurns,
101
- maxTimeMinutes: maxTimeMs / 60000,
102
- toolNames: Object.keys(toolsMap),
103
- });
104
- // 4. Main loop (reference: gemini-cli runInternal L667-726)
105
- try {
106
- while (true) {
107
- // 4a. Check termination conditions
108
- const terminationCheck = this.checkTermination(turnCounter, maxTurns, startTime, maxTimeMs, signal);
109
- if (terminationCheck) {
110
- terminateReason = terminationCheck;
111
- break;
112
- }
113
- // 4b. Call LLM
114
- this.emitEvent(onEvent, 'thought_chunk', definition.name, {
115
- turn: turnCounter,
116
- message: `Turn ${turnCounter + 1}/${maxTurns}: Calling model...`,
117
- });
118
- const chatResult = await this.llm.chatWithTools(messages, toolsMap, signal);
119
- // 4c. Process assistant response
120
- const assistantMessage = chatResult.message;
121
- messages.push(assistantMessage);
122
- // 4d. Handle text-only response (no tool_calls)
123
- if (!assistantMessage.tool_calls?.length) {
124
- // The LLM responded with text instead of calling any tool.
125
- // This means it didn't call complete_task → ERROR_NO_COMPLETE_TASK.
126
- // But if there's meaningful text content, we can treat it as the final result.
127
- const textContent = typeof assistantMessage.content === 'string'
128
- ? assistantMessage.content
129
- : null;
130
- if (textContent) {
131
- // The LLM gave a text answer but didn't follow the protocol.
132
- // Treat it as a soft completion.
133
- this.emitEvent(onEvent, 'thought_chunk', definition.name, {
134
- message: 'Model returned text content without calling complete_task. Treating as final answer.',
135
- });
136
- finalResult = textContent;
137
- terminateReason = types_1.TM_GOAL;
138
- }
139
- else {
140
- terminateReason = types_1.TM_ERROR_NO_COMPLETE_TASK;
141
- }
142
- break;
143
- }
144
- // 4e. Process each tool_call
145
- let taskCompleted = false;
146
- for (const toolCall of assistantMessage.tool_calls) {
147
- const toolName = toolCall.function.name;
148
- let toolArgs;
149
- try {
150
- toolArgs = JSON.parse(toolCall.function.arguments);
151
- }
152
- catch {
153
- // Handle malformed JSON (common with LLM outputs)
154
- toolArgs = {};
155
- }
156
- // Check if this is the termination signal
157
- if (toolName === types_1.COMPLETE_TASK_TOOL_NAME) {
158
- finalResult = JSON.stringify(toolArgs);
159
- taskCompleted = true;
160
- // Append tool response to messages (for history completeness)
161
- messages.push({
162
- role: 'tool',
163
- tool_call_id: toolCall.id,
164
- name: types_1.COMPLETE_TASK_TOOL_NAME,
165
- content: JSON.stringify({ result: finalResult, taskCompleted: true }),
166
- });
167
- break;
168
- }
169
- // Execute the tool via registry
170
- this.emitEvent(onEvent, 'tool_call_start', definition.name, {
171
- tool: toolName,
172
- args: toolArgs,
173
- turn: turnCounter,
174
- }, toolName);
175
- let toolResult;
176
- try {
177
- const toolContext = {
178
- runtime: globalThis.__runtime ?? {},
179
- cwd: definition.cwd ?? process.cwd(),
180
- readOnlyPaths: definition.readOnlyPaths,
181
- };
182
- toolResult = await localRegistry.execute(toolName, toolArgs, toolContext);
183
- }
184
- catch (error) {
185
- toolResult = { error: error.message || String(error), isError: true };
186
- this.emitEvent(onEvent, 'agent_error', definition.name, {
187
- tool: toolName,
188
- error: error.message,
189
- });
190
- }
191
- this.emitEvent(onEvent, 'tool_call_end', definition.name, {
192
- tool: toolName,
193
- result: typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult),
194
- turn: turnCounter,
195
- }, toolName);
196
- // Append tool response to messages
197
- messages.push({
198
- role: 'tool',
199
- tool_call_id: toolCall.id,
200
- name: toolName,
201
- content: typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult),
202
- });
203
- }
204
- if (taskCompleted) {
205
- terminateReason = types_1.TM_GOAL;
206
- break;
207
- }
208
- turnCounter++;
209
- }
210
- }
211
- catch (error) {
212
- // Check if it's an abort error
213
- if (error?.name === 'AbortError' || signal?.aborted) {
214
- terminateReason = types_1.TM_ABORTED;
215
- }
216
- else {
217
- terminateReason = types_1.TM_ERROR;
218
- finalResult = null;
219
- // Enhanced error logging for debugging
220
- const errorDetail = error instanceof index_1.InvokeError
221
- ? `[InvokeError type=${error.type} retryable=${error.retryable}] ${error.message}`
222
- : error?.message || String(error);
223
- console.error(`[AgentLoop] Agent "${definition.name}" terminated with ERROR: ${errorDetail}`);
224
- if (error instanceof index_1.InvokeError && error.rawResponse) {
225
- console.error(`[AgentLoop] InvokeError rawResponse:`, JSON.stringify(error.rawResponse).slice(0, 500));
226
- }
227
- this.emitEvent(onEvent, 'agent_error', definition.name, {
228
- error: errorDetail,
229
- errorType: error?.type || error?.constructor?.name || 'unknown',
230
- phase: 'execution',
231
- turn: turnCounter,
232
- });
233
- }
234
- }
235
- // 5. Emit end event
236
- this.emitEvent(onEvent, 'agent_end', definition.name, {
237
- terminateReason,
238
- turnCount: turnCounter,
239
- durationMs: Date.now() - startTime,
240
- output: finalResult ?? undefined,
241
- });
242
- // 6. Return result
243
- return {
244
- success: terminateReason === types_1.TM_GOAL,
245
- output: finalResult ?? undefined,
246
- terminateReason,
247
- turnCount: turnCounter,
248
- durationMs: Date.now() - startTime,
249
- error: terminateReason !== types_1.TM_GOAL
250
- ? `Agent terminated: ${terminateReason}${terminateReason === types_1.TM_ERROR_NO_COMPLETE_TASK ? ' (model stopped calling tools without complete_task)' : ''}`
251
- : undefined,
252
- };
253
- }
254
- /**
255
- * Check if the agent should terminate.
256
- * Returns a terminate reason if termination is needed, null otherwise.
257
- */
258
- checkTermination(turnCounter, maxTurns, startTime, maxTimeMs, signal) {
259
- if (turnCounter >= maxTurns) {
260
- return types_1.TM_MAX_TURNS;
261
- }
262
- if (signal?.aborted) {
263
- return types_1.TM_ABORTED;
264
- }
265
- if (Date.now() - startTime >= maxTimeMs) {
266
- return types_1.TM_TIMEOUT;
267
- }
268
- return null;
269
- }
270
- /**
271
- * Emit an event to the callback, if provided.
272
- */
273
- emitEvent(onEvent, type, streamId, data, toolName) {
274
- if (onEvent) {
275
- const processed = (type === 'tool_call_start' || type === 'tool_call_end')
276
- ? truncateFileContent(data, toolName)
277
- : data;
278
- onEvent({ type, streamId, data: processed });
279
- }
280
- }
281
- }
282
- exports.AgentLoop = AgentLoop;
@@ -1,40 +0,0 @@
1
- /**
2
- * RuntimeEnvironment — runtime environment detection
3
- *
4
- * Detects available system binaries (git/codegraph/playwright/node),
5
- * and provides config paths (env).
6
- *
7
- * Tools (core/tools/*) get paths via ToolExecutionContext.runtime,
8
- * instead of resolving binaries themselves.
9
- *
10
- * Design decisions:
11
- * D02: Layer 1: RuntimeEnvironment provides binary paths
12
- * Layer 2: Tool execute() gets paths from runtime
13
- * Layer 3: Skill only ctx.tools.call(), no path awareness
14
- * D04: Business-specific paths (keveWikiDir/reposBaseDir) removed from core.
15
- * Agent package can add them in its own runtime extension.
16
- */
17
- export interface RuntimeEnvironment {
18
- /** Git binary path */
19
- gitBin: string;
20
- /** Codegraph binary path */
21
- codegraphBin: string;
22
- /** Playwright binary path (usually in agent's node_modules/.bin) */
23
- playwrightBin: string;
24
- /** Node binary path */
25
- nodeBin: string;
26
- /** Package manager (pnpm/npm/yarn) */
27
- packageManager: string;
28
- /** Environment variables (tokens, configs) */
29
- env: Record<string, string>;
30
- }
31
- /**
32
- * Detect the runtime environment.
33
- *
34
- * Scans for binaries, loads env vars.
35
- * Called once at startup (entry.ts) and passed to Pipeline → SkillContext.
36
- *
37
- * @param cwd - Starting directory (defaults to process.cwd())
38
- * @param agentDir - Agent package directory for finding node_modules binaries
39
- */
40
- export declare function detectRuntimeEnvironment(cwd?: string, agentDir?: string): RuntimeEnvironment;