@tyvm/knowhow 0.0.69 ā 0.0.70
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/docs/shell-commands.md +174 -0
- package/package.json +1 -1
- package/src/agents/base/base.ts +1 -3
- package/src/agents/developer/developer.ts +21 -13
- package/src/agents/tools/agentCall.ts +4 -2
- package/src/agents/tools/fileSearch.ts +5 -1
- package/src/agents/tools/startAgentTask.ts +131 -22
- package/src/chat/CliChatService.ts +57 -11
- package/src/chat/modules/AgentModule.ts +72 -12
- package/src/chat/modules/CustomCommandsModule.ts +79 -0
- package/src/chat/modules/InternalChatModule.ts +11 -1
- package/src/chat/modules/ShellCommandModule.ts +96 -0
- package/src/chat/modules/index.ts +1 -0
- package/src/chat/types.ts +14 -2
- package/src/chat.ts +16 -13
- package/src/cli.ts +16 -6
- package/src/clients/anthropic.ts +41 -90
- package/src/clients/gemini.ts +445 -87
- package/src/clients/index.ts +125 -0
- package/src/clients/knowhow.ts +81 -0
- package/src/clients/openai.ts +256 -145
- package/src/clients/pricing/anthropic.ts +90 -0
- package/src/clients/pricing/google.ts +65 -0
- package/src/clients/pricing/index.ts +4 -0
- package/src/clients/pricing/openai.ts +134 -0
- package/src/clients/pricing/xai.ts +62 -0
- package/src/clients/types.ts +170 -1
- package/src/clients/xai.ts +275 -46
- package/src/config.ts +61 -15
- package/src/embeddings.ts +9 -1
- package/src/microphone.ts +15 -16
- package/src/migrations.ts +151 -0
- package/src/plugins/AgentsMdPlugin.ts +118 -0
- package/src/plugins/PluginBase.ts +8 -0
- package/src/plugins/downloader/downloader.ts +5 -6
- package/src/plugins/embedding.ts +10 -8
- package/src/plugins/exec.ts +70 -0
- package/src/plugins/github.ts +120 -74
- package/src/plugins/language.ts +11 -13
- package/src/plugins/plugins.ts +25 -4
- package/src/plugins/tmux.ts +132 -0
- package/src/plugins/types.ts +1 -0
- package/src/plugins/vim.ts +14 -1
- package/src/services/AgentSyncFs.ts +417 -0
- package/src/services/{AgentSynchronization.ts ā AgentSyncKnowhowWeb.ts} +2 -2
- package/src/services/EventService.ts +0 -1
- package/src/services/KnowhowClient.ts +106 -0
- package/src/services/index.ts +4 -2
- package/src/types.ts +57 -4
- package/src/worker.ts +11 -6
- package/tests/manual/modalities/README.md +157 -0
- package/tests/manual/modalities/google.modalities.test.ts +335 -0
- package/tests/manual/modalities/openai.modalities.test.ts +329 -0
- package/tests/manual/modalities/streaming.test.ts +260 -0
- package/tests/manual/modalities/xai.modalities.test.ts +307 -0
- package/tests/plugins/language/languagePlugin-content-triggers.test.ts +5 -5
- package/tests/plugins/language/languagePlugin-integration.test.ts +1 -1
- package/tests/plugins/language/languagePlugin.test.ts +17 -8
- package/ts_build/package.json +1 -1
- package/ts_build/src/agents/base/base.js +1 -1
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/developer/developer.js +21 -12
- package/ts_build/src/agents/developer/developer.js.map +1 -1
- package/ts_build/src/agents/tools/agentCall.js +4 -2
- package/ts_build/src/agents/tools/agentCall.js.map +1 -1
- package/ts_build/src/agents/tools/executeScript/index.d.ts +1 -1
- package/ts_build/src/agents/tools/fileSearch.js +2 -1
- package/ts_build/src/agents/tools/fileSearch.js.map +1 -1
- package/ts_build/src/agents/tools/github/index.d.ts +1 -1
- package/ts_build/src/agents/tools/startAgentTask.d.ts +2 -1
- package/ts_build/src/agents/tools/startAgentTask.js +118 -17
- package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
- package/ts_build/src/chat/CliChatService.d.ts +4 -0
- package/ts_build/src/chat/CliChatService.js +39 -5
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +4 -1
- package/ts_build/src/chat/modules/AgentModule.js +49 -11
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/chat/modules/CustomCommandsModule.d.ts +9 -0
- package/ts_build/src/chat/modules/CustomCommandsModule.js +58 -0
- package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -0
- package/ts_build/src/chat/modules/InternalChatModule.d.ts +2 -0
- package/ts_build/src/chat/modules/InternalChatModule.js +10 -0
- package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
- package/ts_build/src/chat/modules/ShellCommandModule.d.ts +8 -0
- package/ts_build/src/chat/modules/ShellCommandModule.js +83 -0
- package/ts_build/src/chat/modules/ShellCommandModule.js.map +1 -0
- package/ts_build/src/chat/modules/index.d.ts +1 -0
- package/ts_build/src/chat/modules/index.js +3 -1
- package/ts_build/src/chat/modules/index.js.map +1 -1
- package/ts_build/src/chat/types.d.ts +11 -1
- package/ts_build/src/chat.js +16 -13
- package/ts_build/src/chat.js.map +1 -1
- package/ts_build/src/cli.js +10 -3
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/anthropic.d.ts +5 -1
- package/ts_build/src/clients/anthropic.js +18 -91
- package/ts_build/src/clients/anthropic.js.map +1 -1
- package/ts_build/src/clients/gemini.d.ts +80 -2
- package/ts_build/src/clients/gemini.js +336 -74
- package/ts_build/src/clients/gemini.js.map +1 -1
- package/ts_build/src/clients/index.d.ts +9 -1
- package/ts_build/src/clients/index.js +65 -0
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/clients/knowhow.d.ts +9 -1
- package/ts_build/src/clients/knowhow.js +43 -0
- package/ts_build/src/clients/knowhow.js.map +1 -1
- package/ts_build/src/clients/openai.d.ts +9 -1
- package/ts_build/src/clients/openai.js +201 -133
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/anthropic.d.ts +17 -0
- package/ts_build/src/clients/pricing/anthropic.js +93 -0
- package/ts_build/src/clients/pricing/anthropic.js.map +1 -0
- package/ts_build/src/clients/pricing/google.d.ts +73 -0
- package/ts_build/src/clients/pricing/google.js +68 -0
- package/ts_build/src/clients/pricing/google.js.map +1 -0
- package/ts_build/src/clients/pricing/index.d.ts +4 -0
- package/ts_build/src/clients/pricing/index.js +14 -0
- package/ts_build/src/clients/pricing/index.js.map +1 -0
- package/ts_build/src/clients/pricing/openai.d.ts +7 -0
- package/ts_build/src/clients/pricing/openai.js +137 -0
- package/ts_build/src/clients/pricing/openai.js.map +1 -0
- package/ts_build/src/clients/pricing/xai.d.ts +26 -0
- package/ts_build/src/clients/pricing/xai.js +59 -0
- package/ts_build/src/clients/pricing/xai.js.map +1 -0
- package/ts_build/src/clients/types.d.ts +135 -0
- package/ts_build/src/clients/xai.d.ts +9 -1
- package/ts_build/src/clients/xai.js +178 -46
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/config.d.ts +1 -0
- package/ts_build/src/config.js +45 -16
- package/ts_build/src/config.js.map +1 -1
- package/ts_build/src/embeddings.js +8 -1
- package/ts_build/src/embeddings.js.map +1 -1
- package/ts_build/src/microphone.js +7 -9
- package/ts_build/src/microphone.js.map +1 -1
- package/ts_build/src/migrations.d.ts +17 -0
- package/ts_build/src/migrations.js +86 -0
- package/ts_build/src/migrations.js.map +1 -0
- package/ts_build/src/plugins/AgentsMdPlugin.d.ts +13 -0
- package/ts_build/src/plugins/AgentsMdPlugin.js +118 -0
- package/ts_build/src/plugins/AgentsMdPlugin.js.map +1 -0
- package/ts_build/src/plugins/PluginBase.d.ts +1 -0
- package/ts_build/src/plugins/PluginBase.js +3 -0
- package/ts_build/src/plugins/PluginBase.js.map +1 -1
- package/ts_build/src/plugins/downloader/downloader.js +5 -5
- package/ts_build/src/plugins/downloader/downloader.js.map +1 -1
- package/ts_build/src/plugins/embedding.js +9 -8
- package/ts_build/src/plugins/embedding.js.map +1 -1
- package/ts_build/src/plugins/exec.d.ts +10 -0
- package/ts_build/src/plugins/exec.js +56 -0
- package/ts_build/src/plugins/exec.js.map +1 -0
- package/ts_build/src/plugins/github.js +93 -51
- package/ts_build/src/plugins/github.js.map +1 -1
- package/ts_build/src/plugins/language.js +14 -11
- package/ts_build/src/plugins/language.js.map +1 -1
- package/ts_build/src/plugins/plugins.d.ts +1 -0
- package/ts_build/src/plugins/plugins.js +19 -1
- package/ts_build/src/plugins/plugins.js.map +1 -1
- package/ts_build/src/plugins/tmux.d.ts +14 -0
- package/ts_build/src/plugins/tmux.js +108 -0
- package/ts_build/src/plugins/tmux.js.map +1 -0
- package/ts_build/src/plugins/types.d.ts +1 -0
- package/ts_build/src/plugins/vim.js +11 -1
- package/ts_build/src/plugins/vim.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.d.ts +34 -0
- package/ts_build/src/services/AgentSyncFs.js +325 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -0
- package/ts_build/src/services/AgentSyncKnowhowWeb.d.ts +29 -0
- package/ts_build/src/services/AgentSyncKnowhowWeb.js +178 -0
- package/ts_build/src/services/AgentSyncKnowhowWeb.js.map +1 -0
- package/ts_build/src/services/AgentSynchronization.d.ts +1 -1
- package/ts_build/src/services/AgentSynchronization.js +3 -3
- package/ts_build/src/services/AgentSynchronization.js.map +1 -1
- package/ts_build/src/services/EventService.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +9 -1
- package/ts_build/src/services/KnowhowClient.js +58 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/index.d.ts +2 -1
- package/ts_build/src/services/index.js +2 -1
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/types.d.ts +26 -1
- package/ts_build/src/types.js +45 -4
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/utils/PersistentInputManager.d.ts +28 -0
- package/ts_build/src/utils/PersistentInputManager.js +293 -0
- package/ts_build/src/utils/PersistentInputManager.js.map +1 -0
- package/ts_build/src/worker.js +2 -2
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/tests/manual/modalities/google.modalities.test.d.ts +1 -0
- package/ts_build/tests/manual/modalities/google.modalities.test.js +252 -0
- package/ts_build/tests/manual/modalities/google.modalities.test.js.map +1 -0
- package/ts_build/tests/manual/modalities/openai.modalities.test.d.ts +1 -0
- package/ts_build/tests/manual/modalities/openai.modalities.test.js +252 -0
- package/ts_build/tests/manual/modalities/openai.modalities.test.js.map +1 -0
- package/ts_build/tests/manual/modalities/streaming.test.d.ts +1 -0
- package/ts_build/tests/manual/modalities/streaming.test.js +206 -0
- package/ts_build/tests/manual/modalities/streaming.test.js.map +1 -0
- package/ts_build/tests/manual/modalities/xai.modalities.test.d.ts +1 -0
- package/ts_build/tests/manual/modalities/xai.modalities.test.js +226 -0
- package/ts_build/tests/manual/modalities/xai.modalities.test.js.map +1 -0
- package/ts_build/tests/manual/persistent-input-test.d.ts +1 -0
- package/ts_build/tests/manual/persistent-input-test.js +35 -0
- package/ts_build/tests/manual/persistent-input-test.js.map +1 -0
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +5 -5
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +1 -1
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +1 -1
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +1 -1
- package/ts_build/tests/plugins/language/languagePlugin.test.js +17 -7
- package/ts_build/tests/plugins/language/languagePlugin.test.js.map +1 -1
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming Text Manual Test
|
|
3
|
+
*
|
|
4
|
+
* Tests streaming text generation across all providers:
|
|
5
|
+
* 1. OpenAI - GPT-4o streaming
|
|
6
|
+
* 2. Anthropic - Claude streaming
|
|
7
|
+
* 3. Google - Gemini streaming
|
|
8
|
+
* 4. XAI - Grok streaming
|
|
9
|
+
*
|
|
10
|
+
* Run with:
|
|
11
|
+
* npx jest tests/manual/modalities/streaming.test.ts --testTimeout=120000
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import * as fs from "fs";
|
|
15
|
+
import * as path from "path";
|
|
16
|
+
import { AIClient } from "../../../src/clients";
|
|
17
|
+
import { Models } from "../../../src/types";
|
|
18
|
+
|
|
19
|
+
const OUTPUT_DIR = path.join(__dirname, "outputs", "streaming");
|
|
20
|
+
|
|
21
|
+
function ensureOutputDir() {
|
|
22
|
+
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe("Streaming Text Generation", () => {
|
|
26
|
+
let client: AIClient;
|
|
27
|
+
|
|
28
|
+
beforeAll(() => {
|
|
29
|
+
ensureOutputDir();
|
|
30
|
+
client = new AIClient();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// āāā 1. OpenAI Streaming āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
34
|
+
|
|
35
|
+
test("1. OpenAI GPT-4o ā streaming text generation", async () => {
|
|
36
|
+
const outputPath = path.join(OUTPUT_DIR, "openai-streaming.txt");
|
|
37
|
+
if (fs.existsSync(outputPath)) {
|
|
38
|
+
console.log(`Skipping: output already exists at ${outputPath}`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!process.env.OPENAI_KEY) {
|
|
43
|
+
console.log("Skipping: OPENAI_KEY not set");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const prompt = "Count from 1 to 10, one number per line.";
|
|
48
|
+
|
|
49
|
+
// Use the raw OpenAI client for streaming
|
|
50
|
+
const openaiClient = client.clients.openai as any;
|
|
51
|
+
if (!openaiClient) {
|
|
52
|
+
console.log("Skipping: OpenAI client not available");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const stream = await openaiClient.client.chat.completions.create({
|
|
57
|
+
model: Models.openai.GPT_4o_Mini,
|
|
58
|
+
messages: [{ role: "user", content: prompt }],
|
|
59
|
+
stream: true,
|
|
60
|
+
max_tokens: 100,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
let fullText = "";
|
|
64
|
+
const chunks: string[] = [];
|
|
65
|
+
|
|
66
|
+
for await (const chunk of stream) {
|
|
67
|
+
const content = chunk.choices[0]?.delta?.content || "";
|
|
68
|
+
if (content) {
|
|
69
|
+
fullText += content;
|
|
70
|
+
chunks.push(content);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fs.writeFileSync(
|
|
75
|
+
outputPath,
|
|
76
|
+
`Full text:\n${fullText}\n\nChunks (${chunks.length}):\n${chunks.join(" | ")}`
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
console.log(`ā
OpenAI streaming completed`);
|
|
80
|
+
console.log(` Output saved to: ${outputPath}`);
|
|
81
|
+
console.log(` Total chunks: ${chunks.length}`);
|
|
82
|
+
console.log(` Full text: ${fullText.substring(0, 100)}...`);
|
|
83
|
+
|
|
84
|
+
expect(fullText).toBeTruthy();
|
|
85
|
+
expect(chunks.length).toBeGreaterThan(0);
|
|
86
|
+
expect(fullText).toContain("1");
|
|
87
|
+
expect(fullText).toContain("10");
|
|
88
|
+
}, 60000);
|
|
89
|
+
|
|
90
|
+
// āāā 2. Anthropic Streaming āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
91
|
+
|
|
92
|
+
test("2. Anthropic Claude ā streaming text generation", async () => {
|
|
93
|
+
const outputPath = path.join(OUTPUT_DIR, "anthropic-streaming.txt");
|
|
94
|
+
if (fs.existsSync(outputPath)) {
|
|
95
|
+
console.log(`Skipping: output already exists at ${outputPath}`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
100
|
+
console.log("Skipping: ANTHROPIC_API_KEY not set");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const prompt = "Count from 1 to 10, one number per line.";
|
|
105
|
+
|
|
106
|
+
const anthropicClient = client.clients.anthropic as any;
|
|
107
|
+
if (!anthropicClient) {
|
|
108
|
+
console.log("Skipping: Anthropic client not available");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const stream = await anthropicClient.client.messages.create({
|
|
113
|
+
model: Models.anthropic.Haiku4_5,
|
|
114
|
+
max_tokens: 100,
|
|
115
|
+
messages: [{ role: "user", content: prompt }],
|
|
116
|
+
stream: true,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
let fullText = "";
|
|
120
|
+
const chunks: string[] = [];
|
|
121
|
+
|
|
122
|
+
for await (const chunk of stream) {
|
|
123
|
+
if (
|
|
124
|
+
chunk.type === "content_block_delta" &&
|
|
125
|
+
chunk.delta.type === "text_delta"
|
|
126
|
+
) {
|
|
127
|
+
const content = chunk.delta.text;
|
|
128
|
+
if (content) {
|
|
129
|
+
fullText += content;
|
|
130
|
+
chunks.push(content);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fs.writeFileSync(
|
|
136
|
+
outputPath,
|
|
137
|
+
`Full text:\n${fullText}\n\nChunks (${chunks.length}):\n${chunks.join(" | ")}`
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
console.log(`ā
Anthropic streaming completed`);
|
|
141
|
+
console.log(` Output saved to: ${outputPath}`);
|
|
142
|
+
console.log(` Total chunks: ${chunks.length}`);
|
|
143
|
+
console.log(` Full text: ${fullText.substring(0, 100)}...`);
|
|
144
|
+
|
|
145
|
+
expect(fullText).toBeTruthy();
|
|
146
|
+
expect(chunks.length).toBeGreaterThan(0);
|
|
147
|
+
expect(fullText).toContain("1");
|
|
148
|
+
expect(fullText).toContain("10");
|
|
149
|
+
}, 60000);
|
|
150
|
+
|
|
151
|
+
// āāā 3. Google Gemini Streaming āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
152
|
+
|
|
153
|
+
test("3. Google Gemini ā streaming text generation", async () => {
|
|
154
|
+
const outputPath = path.join(OUTPUT_DIR, "google-streaming.txt");
|
|
155
|
+
if (fs.existsSync(outputPath)) {
|
|
156
|
+
console.log(`Skipping: output already exists at ${outputPath}`);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!process.env.GEMINI_API_KEY) {
|
|
161
|
+
console.log("Skipping: GEMINI_API_KEY not set");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const prompt = "Count from 1 to 10, one number per line.";
|
|
166
|
+
|
|
167
|
+
const geminiClient = client.clients.google as any;
|
|
168
|
+
if (!geminiClient) {
|
|
169
|
+
console.log("Skipping: Google client not available");
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const result = await geminiClient.client.models.generateContentStream({
|
|
174
|
+
model: Models.google.Gemini_20_Flash,
|
|
175
|
+
contents: [{ role: 'user', parts: [{ text: prompt }] }]
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
let fullText = "";
|
|
179
|
+
const chunks: string[] = [];
|
|
180
|
+
|
|
181
|
+
for await (const chunk of result) {
|
|
182
|
+
const chunkText = chunk.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
|
183
|
+
if (chunkText) {
|
|
184
|
+
fullText += chunkText;
|
|
185
|
+
chunks.push(chunkText);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
fs.writeFileSync(
|
|
190
|
+
outputPath,
|
|
191
|
+
`Full text:\n${fullText}\n\nChunks (${chunks.length}):\n${chunks.join(" | ")}`
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
console.log(`ā
Google Gemini streaming completed`);
|
|
195
|
+
console.log(` Output saved to: ${outputPath}`);
|
|
196
|
+
console.log(` Total chunks: ${chunks.length}`);
|
|
197
|
+
console.log(` Full text: ${fullText.substring(0, 100)}...`);
|
|
198
|
+
|
|
199
|
+
expect(fullText).toBeTruthy();
|
|
200
|
+
expect(chunks.length).toBeGreaterThan(0);
|
|
201
|
+
expect(fullText).toContain("1");
|
|
202
|
+
expect(fullText).toContain("10");
|
|
203
|
+
}, 60000);
|
|
204
|
+
|
|
205
|
+
// āāā 4. XAI Grok Streaming āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
206
|
+
|
|
207
|
+
test("4. XAI Grok ā streaming text generation", async () => {
|
|
208
|
+
const outputPath = path.join(OUTPUT_DIR, "xai-streaming.txt");
|
|
209
|
+
if (fs.existsSync(outputPath)) {
|
|
210
|
+
console.log(`Skipping: output already exists at ${outputPath}`);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (!process.env.XAI_API_KEY) {
|
|
215
|
+
console.log("Skipping: XAI_API_KEY not set");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const prompt = "Count from 1 to 10, one number per line.";
|
|
220
|
+
|
|
221
|
+
const xaiClient = client.clients.xai as any;
|
|
222
|
+
if (!xaiClient) {
|
|
223
|
+
console.log("Skipping: XAI client not available");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const stream = await xaiClient.client.chat.completions.create({
|
|
228
|
+
model: Models.xai.Grok3MiniFastBeta,
|
|
229
|
+
messages: [{ role: "user", content: prompt }],
|
|
230
|
+
stream: true,
|
|
231
|
+
max_tokens: 100,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
let fullText = "";
|
|
235
|
+
const chunks: string[] = [];
|
|
236
|
+
|
|
237
|
+
for await (const chunk of stream) {
|
|
238
|
+
const content = chunk.choices[0]?.delta?.content || "";
|
|
239
|
+
if (content) {
|
|
240
|
+
fullText += content;
|
|
241
|
+
chunks.push(content);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
fs.writeFileSync(
|
|
246
|
+
outputPath,
|
|
247
|
+
`Full text:\n${fullText}\n\nChunks (${chunks.length}):\n${chunks.join(" | ")}`
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
console.log(`ā
XAI Grok streaming completed`);
|
|
251
|
+
console.log(` Output saved to: ${outputPath}`);
|
|
252
|
+
console.log(` Total chunks: ${chunks.length}`);
|
|
253
|
+
console.log(` Full text: ${fullText.substring(0, 100)}...`);
|
|
254
|
+
|
|
255
|
+
expect(fullText).toBeTruthy();
|
|
256
|
+
expect(chunks.length).toBeGreaterThan(0);
|
|
257
|
+
expect(fullText).toContain("1");
|
|
258
|
+
expect(fullText).toContain("10");
|
|
259
|
+
}, 60000);
|
|
260
|
+
});
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XAI (Grok) Modalities Manual Test
|
|
3
|
+
*
|
|
4
|
+
* Tests:
|
|
5
|
+
* 1. Image generation (grok-imagine-image) ā saved to disk
|
|
6
|
+
* 2. Vision ā send generated image to Grok vision model and describe it
|
|
7
|
+
* 3. Audio generation ā not supported by XAI (documented)
|
|
8
|
+
* 4. Audio transcription ā not supported by XAI (documented)
|
|
9
|
+
* 5. Video generation (grok-imagine-video) ā polls until done, saves URL to disk
|
|
10
|
+
*
|
|
11
|
+
* Run with:
|
|
12
|
+
* npx jest tests/manual/modalities/xai.modalities.test.ts --testTimeout=720000
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import * as fs from "fs";
|
|
16
|
+
import * as path from "path";
|
|
17
|
+
import { AIClient } from "../../../src/clients";
|
|
18
|
+
import { Models } from "../../../src/types";
|
|
19
|
+
|
|
20
|
+
const OUTPUT_DIR = path.join(__dirname, "outputs", "xai");
|
|
21
|
+
|
|
22
|
+
function ensureOutputDir() {
|
|
23
|
+
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe("XAI (Grok) Modalities", () => {
|
|
27
|
+
let client: AIClient;
|
|
28
|
+
|
|
29
|
+
beforeAll(() => {
|
|
30
|
+
if (!process.env.XAI_API_KEY) {
|
|
31
|
+
console.warn("XAI_API_KEY not set ā skipping XAI modality tests");
|
|
32
|
+
}
|
|
33
|
+
ensureOutputDir();
|
|
34
|
+
client = new AIClient();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// āāā 1. Image Generation (grok-imagine-image) āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
38
|
+
|
|
39
|
+
test("1. XAI grok-imagine-image ā generate image and save to disk", async () => {
|
|
40
|
+
if (!process.env.XAI_API_KEY) {
|
|
41
|
+
console.log("Skipping: XAI_API_KEY not set");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const prompt =
|
|
46
|
+
"A breathtaking aerial view of a neon-lit futuristic city at night, " +
|
|
47
|
+
"flying cars, holographic billboards, cyberpunk aesthetic";
|
|
48
|
+
|
|
49
|
+
const response = await client.createImageGeneration("xai", {
|
|
50
|
+
model: "grok-imagine-image",
|
|
51
|
+
prompt,
|
|
52
|
+
n: 1,
|
|
53
|
+
response_format: "b64_json",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(response.data.length).toBeGreaterThan(0);
|
|
57
|
+
|
|
58
|
+
const imageData = response.data[0];
|
|
59
|
+
const outputPath = path.join(OUTPUT_DIR, "aurora-output.png");
|
|
60
|
+
|
|
61
|
+
if (imageData.b64_json) {
|
|
62
|
+
const buffer = Buffer.from(imageData.b64_json, "base64");
|
|
63
|
+
fs.writeFileSync(outputPath, buffer);
|
|
64
|
+
console.log(`ā
Image saved to: ${outputPath}`);
|
|
65
|
+
console.log(` Size: ${buffer.length} bytes`);
|
|
66
|
+
} else if (imageData.url) {
|
|
67
|
+
fs.writeFileSync(
|
|
68
|
+
path.join(OUTPUT_DIR, "aurora-output-url.txt"),
|
|
69
|
+
imageData.url
|
|
70
|
+
);
|
|
71
|
+
console.log(`ā
Image URL saved: ${imageData.url}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
console.log(` Estimated cost: $${response.usd_cost?.toFixed(6)}`);
|
|
75
|
+
|
|
76
|
+
expect(response.created).toBeGreaterThan(0);
|
|
77
|
+
expect(response.data.length).toBeGreaterThan(0);
|
|
78
|
+
}, 90000);
|
|
79
|
+
|
|
80
|
+
// āāā 2. Vision ā send generated image to Grok Vision āāāāāāāāāāāāāāāāāāāāāāāā
|
|
81
|
+
|
|
82
|
+
test("2. XAI Grok Vision ā describe the generated image", async () => {
|
|
83
|
+
if (!process.env.XAI_API_KEY) {
|
|
84
|
+
console.log("Skipping: XAI_API_KEY not set");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const imagePath = path.join(OUTPUT_DIR, "aurora-output.png");
|
|
89
|
+
if (!fs.existsSync(imagePath)) {
|
|
90
|
+
console.log(
|
|
91
|
+
"Skipping: aurora-output.png not found ā run image generation test first"
|
|
92
|
+
);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const imageBuffer = fs.readFileSync(imagePath);
|
|
97
|
+
const base64Image = imageBuffer.toString("base64");
|
|
98
|
+
const dataUrl = `data:image/png;base64,${base64Image}`;
|
|
99
|
+
|
|
100
|
+
const response = await client.createCompletion("xai", {
|
|
101
|
+
model: Models.xai.Grok2Vision1212,
|
|
102
|
+
messages: [
|
|
103
|
+
{
|
|
104
|
+
role: "user",
|
|
105
|
+
content: [
|
|
106
|
+
{
|
|
107
|
+
type: "text",
|
|
108
|
+
text: "Please describe this image in detail. What do you see?",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
type: "image_url",
|
|
112
|
+
image_url: { url: dataUrl },
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
max_tokens: 500,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const description = response.choices[0]?.message?.content || "";
|
|
121
|
+
const outputPath = path.join(OUTPUT_DIR, "vision-description.txt");
|
|
122
|
+
fs.writeFileSync(outputPath, description);
|
|
123
|
+
|
|
124
|
+
console.log(`ā
Vision description saved to: ${outputPath}`);
|
|
125
|
+
console.log(` Description: ${description.substring(0, 200)}...`);
|
|
126
|
+
console.log(` Estimated cost: $${response.usd_cost?.toFixed(6)}`);
|
|
127
|
+
|
|
128
|
+
expect(description).toBeTruthy();
|
|
129
|
+
expect(description.length).toBeGreaterThan(10);
|
|
130
|
+
}, 60000);
|
|
131
|
+
|
|
132
|
+
// āāā 3. Audio Generation ā not supported āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
133
|
+
|
|
134
|
+
test("3. XAI Audio Generation ā not supported (expected error)", async () => {
|
|
135
|
+
if (!process.env.XAI_API_KEY) {
|
|
136
|
+
console.log("Skipping: XAI_API_KEY not set");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* XAI does not support audio generation. The client throws an error.
|
|
142
|
+
* This test verifies that the error is thrown correctly and documents
|
|
143
|
+
* the limitation.
|
|
144
|
+
*/
|
|
145
|
+
await expect(
|
|
146
|
+
client.createAudioGeneration("xai", {
|
|
147
|
+
model: "xai-tts",
|
|
148
|
+
input: "Hello world",
|
|
149
|
+
voice: "default",
|
|
150
|
+
})
|
|
151
|
+
).rejects.toThrow();
|
|
152
|
+
|
|
153
|
+
console.log(
|
|
154
|
+
"ā
XAI correctly throws an error for unsupported audio generation"
|
|
155
|
+
);
|
|
156
|
+
}, 15000);
|
|
157
|
+
|
|
158
|
+
// āāā 4. Audio Transcription ā not supported āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
159
|
+
|
|
160
|
+
test("4. XAI Audio Transcription ā not supported (expected error)", async () => {
|
|
161
|
+
if (!process.env.XAI_API_KEY) {
|
|
162
|
+
console.log("Skipping: XAI_API_KEY not set");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* XAI does not support audio transcription. This test verifies the error.
|
|
168
|
+
*/
|
|
169
|
+
const fakeStream = { name: "test.mp3" } as any;
|
|
170
|
+
|
|
171
|
+
await expect(
|
|
172
|
+
client.createAudioTranscription("xai", {
|
|
173
|
+
file: fakeStream,
|
|
174
|
+
model: "whisper",
|
|
175
|
+
})
|
|
176
|
+
).rejects.toThrow();
|
|
177
|
+
|
|
178
|
+
console.log(
|
|
179
|
+
"ā
XAI correctly throws an error for unsupported audio transcription"
|
|
180
|
+
);
|
|
181
|
+
}, 15000);
|
|
182
|
+
|
|
183
|
+
// āāā 5. Video Generation (grok-imagine-video) āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
184
|
+
|
|
185
|
+
test(
|
|
186
|
+
"5. XAI grok-imagine-video ā generate video and save URL to disk",
|
|
187
|
+
async () => {
|
|
188
|
+
if (!process.env.XAI_API_KEY) {
|
|
189
|
+
console.log("Skipping: XAI_API_KEY not set");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const outputPath = path.join(OUTPUT_DIR, "video-output.txt");
|
|
194
|
+
const jobIdPath = path.join(OUTPUT_DIR, "video-job-id.txt");
|
|
195
|
+
|
|
196
|
+
// If final output already exists, skip entirely
|
|
197
|
+
if (fs.existsSync(outputPath)) {
|
|
198
|
+
console.log(`āļø Skipping: output already exists at ${outputPath}`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const apiKey = process.env.XAI_API_KEY!;
|
|
203
|
+
const prompt =
|
|
204
|
+
"A cyberpunk cityscape at night with flying cars and neon lights, " +
|
|
205
|
+
"cinematic camera slowly panning upward to reveal the skyline";
|
|
206
|
+
|
|
207
|
+
// Helper: poll a known request ID until done, then save results
|
|
208
|
+
async function pollAndSave(requestId: string) {
|
|
209
|
+
const maxPollingTime = 20 * 60 * 1000; // 20 minutes
|
|
210
|
+
const pollingInterval = 5000; // 5 seconds
|
|
211
|
+
const startTime = Date.now();
|
|
212
|
+
|
|
213
|
+
console.log(`ā³ Polling request ID: ${requestId}`);
|
|
214
|
+
|
|
215
|
+
while (Date.now() - startTime < maxPollingTime) {
|
|
216
|
+
await new Promise((resolve) => setTimeout(resolve, pollingInterval));
|
|
217
|
+
|
|
218
|
+
const pollResponse = await fetch(
|
|
219
|
+
`https://api.x.ai/v1/videos/${requestId}`,
|
|
220
|
+
{ headers: { Authorization: `Bearer ${apiKey}` } }
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
if (!pollResponse.ok) {
|
|
224
|
+
const errorText = await pollResponse.text();
|
|
225
|
+
throw new Error(`XAI video polling failed: ${pollResponse.status} ${errorText}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const pollData = await pollResponse.json();
|
|
229
|
+
console.log(` Status: ${pollData.status || "unknown"}, has video: ${!!pollData.video}`);
|
|
230
|
+
|
|
231
|
+
// XAI returns video data directly (no status:"done") when complete
|
|
232
|
+
if (pollData.video?.url) {
|
|
233
|
+
const videoUrl = pollData.video.url;
|
|
234
|
+
const outputContent = [
|
|
235
|
+
`Generated at: ${new Date().toISOString()}`,
|
|
236
|
+
`Prompt: ${prompt}`,
|
|
237
|
+
`Request ID: ${requestId}`,
|
|
238
|
+
`Video URL: ${videoUrl}`,
|
|
239
|
+
].join("\n");
|
|
240
|
+
fs.writeFileSync(outputPath, outputContent);
|
|
241
|
+
console.log(`ā
Video URL saved to: ${outputPath}`);
|
|
242
|
+
console.log(` Video URL: ${videoUrl}`);
|
|
243
|
+
|
|
244
|
+
// Clean up job ID file
|
|
245
|
+
if (fs.existsSync(jobIdPath)) fs.unlinkSync(jobIdPath);
|
|
246
|
+
return pollData;
|
|
247
|
+
} else if (pollData.status === "expired") {
|
|
248
|
+
throw new Error("XAI video generation request expired");
|
|
249
|
+
} else if (pollData.status === "failed") {
|
|
250
|
+
throw new Error(`XAI video generation failed: ${JSON.stringify(pollData)}`);
|
|
251
|
+
}
|
|
252
|
+
// pending ā keep polling
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
throw new Error("XAI video generation timed out after 20 minutes of polling");
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// If we already have a request ID from a previous (timed-out) run, resume
|
|
259
|
+
if (fs.existsSync(jobIdPath)) {
|
|
260
|
+
const requestId = fs.readFileSync(jobIdPath, "utf8").trim();
|
|
261
|
+
console.log(`š Resuming poll for existing request ID: ${requestId}`);
|
|
262
|
+
await pollAndSave(requestId);
|
|
263
|
+
expect(fs.existsSync(outputPath)).toBe(true);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Otherwise start a new job
|
|
268
|
+
console.log("ā³ Submitting XAI video generation job...");
|
|
269
|
+
|
|
270
|
+
const startResponse = await fetch("https://api.x.ai/v1/videos/generations", {
|
|
271
|
+
method: "POST",
|
|
272
|
+
headers: {
|
|
273
|
+
"Content-Type": "application/json",
|
|
274
|
+
Authorization: `Bearer ${apiKey}`,
|
|
275
|
+
},
|
|
276
|
+
body: JSON.stringify({
|
|
277
|
+
model: "grok-imagine-video",
|
|
278
|
+
prompt,
|
|
279
|
+
duration: 5,
|
|
280
|
+
aspect_ratio: "16:9",
|
|
281
|
+
}),
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (!startResponse.ok) {
|
|
285
|
+
const errorText = await startResponse.text();
|
|
286
|
+
throw new Error(`XAI video generation start failed: ${startResponse.status} ${errorText}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const startData = await startResponse.json();
|
|
290
|
+
const requestId = startData.request_id;
|
|
291
|
+
|
|
292
|
+
if (!requestId) {
|
|
293
|
+
throw new Error(`No request_id in response: ${JSON.stringify(startData)}`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Persist the request ID so subsequent runs can resume if this run times out
|
|
297
|
+
fs.writeFileSync(jobIdPath, requestId);
|
|
298
|
+
console.log(`š Request ID saved to: ${jobIdPath} (ID: ${requestId})`);
|
|
299
|
+
|
|
300
|
+
await pollAndSave(requestId);
|
|
301
|
+
|
|
302
|
+
expect(fs.existsSync(outputPath)).toBe(true);
|
|
303
|
+
},
|
|
304
|
+
// 25 minute timeout
|
|
305
|
+
1500000
|
|
306
|
+
);
|
|
307
|
+
});
|
|
@@ -82,7 +82,7 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
82
82
|
|
|
83
83
|
mockedReadFile.mockResolvedValue(Buffer.from(fileContentWithTests));
|
|
84
84
|
mockedConfig.mockResolvedValue({
|
|
85
|
-
plugins: [],
|
|
85
|
+
plugins: { enabled: [], disabled: [] },
|
|
86
86
|
modules: [],
|
|
87
87
|
promptsDir: ".knowhow/prompts",
|
|
88
88
|
sources: [],
|
|
@@ -153,7 +153,7 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
153
153
|
|
|
154
154
|
mockedReadFile.mockResolvedValue(Buffer.from(fileContent));
|
|
155
155
|
mockedConfig.mockResolvedValue({
|
|
156
|
-
plugins: [],
|
|
156
|
+
plugins: { enabled: [], disabled: [] },
|
|
157
157
|
modules: [],
|
|
158
158
|
promptsDir: ".knowhow/prompts",
|
|
159
159
|
sources: [],
|
|
@@ -196,7 +196,7 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
196
196
|
// Mock readFile to throw an error
|
|
197
197
|
mockedReadFile.mockRejectedValue(new Error("File not found"));
|
|
198
198
|
mockedConfig.mockResolvedValue({
|
|
199
|
-
plugins: [],
|
|
199
|
+
plugins: { enabled: [], disabled: [] },
|
|
200
200
|
modules: [],
|
|
201
201
|
promptsDir: ".knowhow/prompts",
|
|
202
202
|
sources: [],
|
|
@@ -245,7 +245,7 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
245
245
|
|
|
246
246
|
mockedReadFile.mockResolvedValue(Buffer.from(fileContent));
|
|
247
247
|
mockedConfig.mockResolvedValue({
|
|
248
|
-
plugins: [],
|
|
248
|
+
plugins: { enabled: [], disabled: [] },
|
|
249
249
|
modules: [],
|
|
250
250
|
promptsDir: ".knowhow/prompts",
|
|
251
251
|
sources: [],
|
|
@@ -298,7 +298,7 @@ describe("LanguagePlugin - Content-Based Triggering", () => {
|
|
|
298
298
|
|
|
299
299
|
mockedReadFile.mockResolvedValue(Buffer.from(fileContent));
|
|
300
300
|
mockedConfig.mockResolvedValue({
|
|
301
|
-
plugins: [],
|
|
301
|
+
plugins: { enabled: [], disabled: [] },
|
|
302
302
|
modules: [],
|
|
303
303
|
promptsDir: ".knowhow/prompts",
|
|
304
304
|
sources: [],
|
|
@@ -57,7 +57,7 @@ describe("LanguagePlugin - Integration Tests", () => {
|
|
|
57
57
|
|
|
58
58
|
// Mock config functions
|
|
59
59
|
(getConfig as jest.MockedFunction<typeof getConfig>).mockResolvedValue({
|
|
60
|
-
plugins: [],
|
|
60
|
+
plugins: { enabled: [], disabled: [] },
|
|
61
61
|
} as Config);
|
|
62
62
|
|
|
63
63
|
// Setup language configuration with testing term
|
|
@@ -80,7 +80,9 @@ describe("LanguagePlugin", () => {
|
|
|
80
80
|
mockPluginService.listPlugins = mockListPlugins;
|
|
81
81
|
mockPluginService.call = mockCall;
|
|
82
82
|
|
|
83
|
-
mockedConfig.mockResolvedValue({
|
|
83
|
+
mockedConfig.mockResolvedValue({
|
|
84
|
+
plugins: { enabled: ["github", "asana"], disabled: [] },
|
|
85
|
+
} as Config);
|
|
84
86
|
mockedLanguageConfig.mockResolvedValue({
|
|
85
87
|
test: {
|
|
86
88
|
events: [],
|
|
@@ -162,7 +164,9 @@ describe("LanguagePlugin", () => {
|
|
|
162
164
|
});
|
|
163
165
|
|
|
164
166
|
test("should handle file:post-edit event and emit agent:msg when file pattern matches", async () => {
|
|
165
|
-
mockedConfig.mockResolvedValue({
|
|
167
|
+
mockedConfig.mockResolvedValue({
|
|
168
|
+
plugins: { enabled: ["github"], disabled: [] },
|
|
169
|
+
} as Config);
|
|
166
170
|
mockedLanguageConfig.mockResolvedValue({
|
|
167
171
|
"**/*.ts": {
|
|
168
172
|
events: ["file:post-edit"],
|
|
@@ -241,9 +245,11 @@ describe("LanguagePlugin", () => {
|
|
|
241
245
|
});
|
|
242
246
|
|
|
243
247
|
test("should handle multiple matching patterns for a single file", async () => {
|
|
244
|
-
mockedConfig.mockResolvedValue({
|
|
248
|
+
mockedConfig.mockResolvedValue({
|
|
249
|
+
plugins: { enabled: [], disabled: [] },
|
|
250
|
+
} as Config);
|
|
245
251
|
mockedLanguageConfig.mockResolvedValue({
|
|
246
|
-
"
|
|
252
|
+
"**/*.ts": {
|
|
247
253
|
events: ["file:post-edit"],
|
|
248
254
|
sources: [{ kind: "text", data: ["TypeScript context"] }],
|
|
249
255
|
},
|
|
@@ -308,9 +314,11 @@ describe("LanguagePlugin", () => {
|
|
|
308
314
|
});
|
|
309
315
|
|
|
310
316
|
test("should resolve different source types in event context", async () => {
|
|
311
|
-
mockedConfig.mockResolvedValue({
|
|
317
|
+
mockedConfig.mockResolvedValue({
|
|
318
|
+
plugins: { enabled: ["github"], disabled: [] },
|
|
319
|
+
} as Config);
|
|
312
320
|
mockedLanguageConfig.mockResolvedValue({
|
|
313
|
-
"
|
|
321
|
+
"package.json": {
|
|
314
322
|
events: ["file:post-edit"],
|
|
315
323
|
sources: [
|
|
316
324
|
{ kind: "file", data: ["config/settings.json"] },
|
|
@@ -360,9 +368,10 @@ describe("LanguagePlugin", () => {
|
|
|
360
368
|
|
|
361
369
|
mockPluginService.listPlugins = mockListPlugins;
|
|
362
370
|
|
|
363
|
-
mockedConfig.mockResolvedValue({
|
|
371
|
+
mockedConfig.mockResolvedValue({
|
|
372
|
+
plugins: { enabled: ["github"], disabled: [] },
|
|
373
|
+
} as Config);
|
|
364
374
|
mockedLanguageConfig.mockResolvedValue({});
|
|
365
|
-
|
|
366
375
|
const languagePlugin = new LanguagePlugin({
|
|
367
376
|
Events: mockEventService,
|
|
368
377
|
Plugins: mockPluginService,
|
package/ts_build/package.json
CHANGED
|
@@ -510,7 +510,7 @@ class BaseAgent {
|
|
|
510
510
|
}
|
|
511
511
|
logStatus() {
|
|
512
512
|
const statusMessage = this.getStatusMessage();
|
|
513
|
-
console.log(`\nā ${this.name} status:
|
|
513
|
+
console.log(`\nā ${this.name} status: ${statusMessage}`);
|
|
514
514
|
}
|
|
515
515
|
addPendingMessage(message) {
|
|
516
516
|
if (this.status === this.eventTypes.done) {
|