@tyvm/knowhow 0.0.104 → 0.0.106
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/CONFIG.md +8 -5
- package/package.json +3 -2
- package/scripts/check-model-pricing.ts +509 -0
- package/scripts/compare-openrouter-coverage.ts +576 -0
- package/src/agents/base/base.ts +127 -2
- package/src/agents/tools/execCommand.ts +4 -0
- package/src/agents/tools/executeScript/definition.ts +1 -1
- package/src/agents/tools/index.ts +0 -1
- package/src/agents/tools/list.ts +3 -43
- package/src/agents/tools/writeFile.ts +1 -1
- package/src/auth/browserLogin.ts +9 -4
- package/src/chat/modules/RemoteSyncModule.ts +3 -0
- package/src/cli.ts +31 -1
- package/src/clients/cerebras.ts +10 -0
- package/src/clients/contextLimits.ts +7 -2
- package/src/clients/copilot.ts +23 -0
- package/src/clients/deepseek.ts +16 -0
- package/src/clients/fireworks.ts +15 -0
- package/src/clients/gemini.ts +45 -2
- package/src/clients/github.ts +16 -0
- package/src/clients/groq.ts +15 -0
- package/src/clients/http.ts +190 -6
- package/src/clients/index.ts +215 -9
- package/src/clients/llama.ts +16 -0
- package/src/clients/mistral.ts +16 -0
- package/src/clients/nvidia.ts +16 -0
- package/src/clients/openai.ts +41 -11
- package/src/clients/openrouter.ts +17 -0
- package/src/clients/pricing/anthropic.ts +105 -78
- package/src/clients/pricing/cerebras.ts +11 -0
- package/src/clients/pricing/copilot.ts +60 -0
- package/src/clients/pricing/deepseek.ts +15 -0
- package/src/clients/pricing/fireworks.ts +32 -0
- package/src/clients/pricing/github.ts +69 -0
- package/src/clients/pricing/google.ts +245 -206
- package/src/clients/pricing/groq.ts +56 -0
- package/src/clients/pricing/index.ts +43 -6
- package/src/clients/pricing/llama.ts +18 -0
- package/src/clients/pricing/mistral.ts +34 -0
- package/src/clients/pricing/models.ts +23 -0
- package/src/clients/pricing/nvidia.ts +102 -0
- package/src/clients/pricing/openai.ts +347 -171
- package/src/clients/pricing/openrouter.ts +36 -0
- package/src/clients/pricing/types.ts +110 -0
- package/src/clients/pricing/xai.ts +123 -66
- package/src/clients/types.ts +4 -0
- package/src/clients/xai.ts +152 -2
- package/src/fileSync.ts +8 -2
- package/src/login.ts +11 -3
- package/src/services/AgentSyncFs.ts +36 -12
- package/src/services/KnowhowClient.ts +11 -0
- package/src/services/LazyToolsService.ts +6 -0
- package/src/services/S3.ts +0 -7
- package/src/services/SyncedAgentWatcher.ts +13 -298
- package/src/services/index.ts +1 -0
- package/src/services/modules/index.ts +11 -2
- package/src/services/watchers/FsSyncer.ts +155 -0
- package/src/services/watchers/RemoteSyncer.ts +153 -0
- package/src/services/watchers/index.ts +2 -0
- package/src/types.ts +56 -279
- package/src/worker.ts +174 -0
- package/tests/clients/pricing.test.ts +37 -0
- package/tests/manual/clients/completions.json +838 -226
- package/tests/manual/clients/completions.test.ts +46 -31
- package/ts_build/package.json +3 -2
- package/ts_build/src/agents/base/base.d.ts +17 -1
- package/ts_build/src/agents/base/base.js +82 -1
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/tools/execCommand.js +3 -0
- package/ts_build/src/agents/tools/execCommand.js.map +1 -1
- package/ts_build/src/agents/tools/executeScript/definition.js +1 -1
- package/ts_build/src/agents/tools/executeScript/definition.js.map +1 -1
- package/ts_build/src/agents/tools/index.d.ts +0 -1
- package/ts_build/src/agents/tools/index.js +0 -1
- package/ts_build/src/agents/tools/index.js.map +1 -1
- package/ts_build/src/agents/tools/list.js +3 -38
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
- package/ts_build/src/agents/tools/writeFile.js +1 -1
- package/ts_build/src/agents/tools/writeFile.js.map +1 -1
- package/ts_build/src/ai.d.ts +1 -1
- package/ts_build/src/auth/browserLogin.d.ts +2 -1
- package/ts_build/src/auth/browserLogin.js +10 -3
- package/ts_build/src/auth/browserLogin.js.map +1 -1
- package/ts_build/src/chat/modules/RemoteSyncModule.js +1 -0
- package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
- package/ts_build/src/cli.js +19 -0
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/clients/anthropic.d.ts +1 -82
- package/ts_build/src/clients/cerebras.d.ts +4 -0
- package/ts_build/src/clients/cerebras.js +14 -0
- package/ts_build/src/clients/cerebras.js.map +1 -0
- package/ts_build/src/clients/contextLimits.js +7 -2
- package/ts_build/src/clients/contextLimits.js.map +1 -1
- package/ts_build/src/clients/copilot.d.ts +4 -0
- package/ts_build/src/clients/copilot.js +15 -0
- package/ts_build/src/clients/copilot.js.map +1 -0
- package/ts_build/src/clients/deepseek.d.ts +4 -0
- package/ts_build/src/clients/deepseek.js +15 -0
- package/ts_build/src/clients/deepseek.js.map +1 -0
- package/ts_build/src/clients/fireworks.d.ts +4 -0
- package/ts_build/src/clients/fireworks.js +15 -0
- package/ts_build/src/clients/fireworks.js.map +1 -0
- package/ts_build/src/clients/gemini.d.ts +1 -0
- package/ts_build/src/clients/gemini.js +28 -1
- package/ts_build/src/clients/gemini.js.map +1 -1
- package/ts_build/src/clients/github.d.ts +4 -0
- package/ts_build/src/clients/github.js +15 -0
- package/ts_build/src/clients/github.js.map +1 -0
- package/ts_build/src/clients/groq.d.ts +4 -0
- package/ts_build/src/clients/groq.js +15 -0
- package/ts_build/src/clients/groq.js.map +1 -0
- package/ts_build/src/clients/http.d.ts +22 -1
- package/ts_build/src/clients/http.js +132 -7
- package/ts_build/src/clients/http.js.map +1 -1
- package/ts_build/src/clients/index.d.ts +22 -0
- package/ts_build/src/clients/index.js +150 -5
- package/ts_build/src/clients/index.js.map +1 -1
- package/ts_build/src/clients/llama.d.ts +4 -0
- package/ts_build/src/clients/llama.js +15 -0
- package/ts_build/src/clients/llama.js.map +1 -0
- package/ts_build/src/clients/mistral.d.ts +4 -0
- package/ts_build/src/clients/mistral.js +15 -0
- package/ts_build/src/clients/mistral.js.map +1 -0
- package/ts_build/src/clients/nvidia.d.ts +4 -0
- package/ts_build/src/clients/nvidia.js +15 -0
- package/ts_build/src/clients/nvidia.js.map +1 -0
- package/ts_build/src/clients/openai.d.ts +4 -206
- package/ts_build/src/clients/openai.js +27 -9
- package/ts_build/src/clients/openai.js.map +1 -1
- package/ts_build/src/clients/openrouter.d.ts +4 -0
- package/ts_build/src/clients/openrouter.js +15 -0
- package/ts_build/src/clients/openrouter.js.map +1 -0
- package/ts_build/src/clients/pricing/anthropic.d.ts +26 -78
- package/ts_build/src/clients/pricing/anthropic.js +75 -78
- package/ts_build/src/clients/pricing/anthropic.js.map +1 -1
- package/ts_build/src/clients/pricing/cerebras.d.ts +4 -0
- package/ts_build/src/clients/pricing/cerebras.js +11 -0
- package/ts_build/src/clients/pricing/cerebras.js.map +1 -0
- package/ts_build/src/clients/pricing/copilot.d.ts +5 -0
- package/ts_build/src/clients/pricing/copilot.js +35 -0
- package/ts_build/src/clients/pricing/copilot.js.map +1 -0
- package/ts_build/src/clients/pricing/deepseek.d.ts +5 -0
- package/ts_build/src/clients/pricing/deepseek.js +10 -0
- package/ts_build/src/clients/pricing/deepseek.js.map +1 -0
- package/ts_build/src/clients/pricing/fireworks.d.ts +5 -0
- package/ts_build/src/clients/pricing/fireworks.js +21 -0
- package/ts_build/src/clients/pricing/fireworks.js.map +1 -0
- package/ts_build/src/clients/pricing/github.d.ts +4 -0
- package/ts_build/src/clients/pricing/github.js +58 -0
- package/ts_build/src/clients/pricing/github.js.map +1 -0
- package/ts_build/src/clients/pricing/google.d.ts +59 -6
- package/ts_build/src/clients/pricing/google.js +214 -167
- package/ts_build/src/clients/pricing/google.js.map +1 -1
- package/ts_build/src/clients/pricing/groq.d.ts +5 -0
- package/ts_build/src/clients/pricing/groq.js +41 -0
- package/ts_build/src/clients/pricing/groq.js.map +1 -0
- package/ts_build/src/clients/pricing/index.d.ts +17 -6
- package/ts_build/src/clients/pricing/index.js +65 -10
- package/ts_build/src/clients/pricing/index.js.map +1 -1
- package/ts_build/src/clients/pricing/llama.d.ts +4 -0
- package/ts_build/src/clients/pricing/llama.js +14 -0
- package/ts_build/src/clients/pricing/llama.js.map +1 -0
- package/ts_build/src/clients/pricing/mistral.d.ts +5 -0
- package/ts_build/src/clients/pricing/mistral.js +23 -0
- package/ts_build/src/clients/pricing/mistral.js.map +1 -0
- package/ts_build/src/clients/pricing/models.d.ts +9 -0
- package/ts_build/src/clients/pricing/models.js +19 -0
- package/ts_build/src/clients/pricing/models.js.map +1 -0
- package/ts_build/src/clients/pricing/nvidia.d.ts +8 -0
- package/ts_build/src/clients/pricing/nvidia.js +96 -0
- package/ts_build/src/clients/pricing/nvidia.js.map +1 -0
- package/ts_build/src/clients/pricing/openai.d.ts +86 -197
- package/ts_build/src/clients/pricing/openai.js +294 -168
- package/ts_build/src/clients/pricing/openai.js.map +1 -1
- package/ts_build/src/clients/pricing/openrouter.d.ts +4 -0
- package/ts_build/src/clients/pricing/openrouter.js +29 -0
- package/ts_build/src/clients/pricing/openrouter.js.map +1 -0
- package/ts_build/src/clients/pricing/types.d.ts +46 -0
- package/ts_build/src/clients/pricing/types.js +49 -0
- package/ts_build/src/clients/pricing/types.js.map +1 -0
- package/ts_build/src/clients/pricing/xai.d.ts +39 -64
- package/ts_build/src/clients/pricing/xai.js +93 -60
- package/ts_build/src/clients/pricing/xai.js.map +1 -1
- package/ts_build/src/clients/types.d.ts +1 -0
- package/ts_build/src/clients/xai.d.ts +2 -58
- package/ts_build/src/clients/xai.js +123 -2
- package/ts_build/src/clients/xai.js.map +1 -1
- package/ts_build/src/fileSync.js +7 -2
- package/ts_build/src/fileSync.js.map +1 -1
- package/ts_build/src/login.js +8 -2
- package/ts_build/src/login.js.map +1 -1
- package/ts_build/src/services/AgentSyncFs.js +1 -0
- package/ts_build/src/services/AgentSyncFs.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +1 -0
- package/ts_build/src/services/KnowhowClient.js +7 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/LazyToolsService.d.ts +1 -0
- package/ts_build/src/services/LazyToolsService.js +3 -0
- package/ts_build/src/services/LazyToolsService.js.map +1 -1
- package/ts_build/src/services/S3.js +0 -7
- package/ts_build/src/services/S3.js.map +1 -1
- package/ts_build/src/services/SyncedAgentWatcher.d.ts +0 -51
- package/ts_build/src/services/SyncedAgentWatcher.js +1 -282
- package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -1
- package/ts_build/src/services/index.d.ts +1 -0
- package/ts_build/src/services/index.js +1 -0
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/modules/index.js +41 -1
- package/ts_build/src/services/modules/index.js.map +1 -1
- package/ts_build/src/services/watchers/FsSyncer.d.ts +27 -0
- package/ts_build/src/services/watchers/FsSyncer.js +135 -0
- package/ts_build/src/services/watchers/FsSyncer.js.map +1 -0
- package/ts_build/src/services/watchers/RemoteSyncer.d.ts +28 -0
- package/ts_build/src/services/watchers/RemoteSyncer.js +126 -0
- package/ts_build/src/services/watchers/RemoteSyncer.js.map +1 -0
- package/ts_build/src/services/watchers/index.d.ts +2 -0
- package/ts_build/src/services/watchers/index.js +19 -0
- package/ts_build/src/services/watchers/index.js.map +1 -0
- package/ts_build/src/types.d.ts +163 -124
- package/ts_build/src/types.js +33 -213
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/worker.d.ts +4 -0
- package/ts_build/src/worker.js +140 -0
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/tests/clients/pricing.test.js +21 -0
- package/ts_build/tests/clients/pricing.test.js.map +1 -1
- package/ts_build/tests/manual/clients/completions.test.js +27 -24
- package/ts_build/tests/manual/clients/completions.test.js.map +1 -1
- package/src/clients/pricing/catalog.ts +0 -287
- package/ts_build/src/clients/pricing/catalog.d.ts +0 -28
- package/ts_build/src/clients/pricing/catalog.js +0 -179
- package/ts_build/src/clients/pricing/catalog.js.map +0 -1
|
@@ -121,7 +121,11 @@ export class AgentSyncFs {
|
|
|
121
121
|
/**
|
|
122
122
|
* Update metadata file with current agent state
|
|
123
123
|
*/
|
|
124
|
-
private async updateMetadata(
|
|
124
|
+
private async updateMetadata(
|
|
125
|
+
agent: BaseAgent,
|
|
126
|
+
inProgress: boolean,
|
|
127
|
+
result?: string
|
|
128
|
+
): Promise<void> {
|
|
125
129
|
if (!this.taskPath) return;
|
|
126
130
|
|
|
127
131
|
try {
|
|
@@ -137,7 +141,8 @@ export class AgentSyncFs {
|
|
|
137
141
|
|
|
138
142
|
metadata.threads = agent.getThreads();
|
|
139
143
|
metadata.totalCostUsd = agent.getTotalCostUsd();
|
|
140
|
-
|
|
144
|
+
metadata.tokenUsage = agent.getTokenUsage();
|
|
145
|
+
metadata.agentName = agent.name;
|
|
141
146
|
metadata.inProgress = inProgress;
|
|
142
147
|
metadata.lastUpdate = new Date().toISOString();
|
|
143
148
|
|
|
@@ -147,7 +152,11 @@ export class AgentSyncFs {
|
|
|
147
152
|
await this.writeStatus("completed");
|
|
148
153
|
}
|
|
149
154
|
|
|
150
|
-
await fs.writeFile(
|
|
155
|
+
await fs.writeFile(
|
|
156
|
+
metadataPath,
|
|
157
|
+
JSON.stringify(metadata, null, 2),
|
|
158
|
+
"utf8"
|
|
159
|
+
);
|
|
151
160
|
} catch (error) {
|
|
152
161
|
console.error(`❌ Failed to update metadata:`, error);
|
|
153
162
|
}
|
|
@@ -206,7 +215,9 @@ export class AgentSyncFs {
|
|
|
206
215
|
// Check for new input/messages
|
|
207
216
|
const input = await this.readInput();
|
|
208
217
|
if (input && input !== this.lastInputContent && input.trim() !== "") {
|
|
209
|
-
console.log(
|
|
218
|
+
console.log(
|
|
219
|
+
`📬 New message received via filesystem for task ${this.taskId}`
|
|
220
|
+
);
|
|
210
221
|
this.lastInputContent = input;
|
|
211
222
|
|
|
212
223
|
agent.addPendingUserMessage({
|
|
@@ -234,7 +245,7 @@ export class AgentSyncFs {
|
|
|
234
245
|
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
235
246
|
|
|
236
247
|
const status = await this.readStatus();
|
|
237
|
-
|
|
248
|
+
|
|
238
249
|
if (status === "killed") {
|
|
239
250
|
console.log(`🛑 Agent task ${this.taskId} killed while paused`);
|
|
240
251
|
await agent.kill();
|
|
@@ -314,7 +325,10 @@ export class AgentSyncFs {
|
|
|
314
325
|
console.error(`❌ Error during threadUpdate sync:`, error);
|
|
315
326
|
}
|
|
316
327
|
};
|
|
317
|
-
agent.agentEvents.on(
|
|
328
|
+
agent.agentEvents.on(
|
|
329
|
+
agent.eventTypes.threadUpdate,
|
|
330
|
+
this.threadUpdateHandler
|
|
331
|
+
);
|
|
318
332
|
|
|
319
333
|
// Listen to completion event to finalize task (store reference for cleanup)
|
|
320
334
|
this.doneHandler = (result: string) => {
|
|
@@ -323,7 +337,9 @@ export class AgentSyncFs {
|
|
|
323
337
|
return;
|
|
324
338
|
}
|
|
325
339
|
|
|
326
|
-
console.log(
|
|
340
|
+
console.log(
|
|
341
|
+
`🎯 [AgentSyncFs] Done event received for task: ${this.taskId}`
|
|
342
|
+
);
|
|
327
343
|
|
|
328
344
|
// Store finalization promise so callers can await it (same pattern as AgentSyncKnowhowWeb)
|
|
329
345
|
this.finalizationPromise = (async () => {
|
|
@@ -332,7 +348,9 @@ export class AgentSyncFs {
|
|
|
332
348
|
// This prevents the race where a pending "inProgress: true" metadata write
|
|
333
349
|
// overwrites the finalization write.
|
|
334
350
|
if (this.pendingThreadUpdatePromise) {
|
|
335
|
-
console.log(
|
|
351
|
+
console.log(
|
|
352
|
+
`⏳ [AgentSyncFs] Awaiting pending thread update before finalizing...`
|
|
353
|
+
);
|
|
336
354
|
await this.pendingThreadUpdatePromise.catch(() => {
|
|
337
355
|
// Ignore errors in pending update — we still want to finalize
|
|
338
356
|
});
|
|
@@ -379,7 +397,7 @@ export class AgentSyncFs {
|
|
|
379
397
|
private static async cleanupOldTasks(): Promise<void> {
|
|
380
398
|
try {
|
|
381
399
|
const agentsPath = AgentSyncFs.sharedBasePath;
|
|
382
|
-
|
|
400
|
+
|
|
383
401
|
// Check if directory exists
|
|
384
402
|
try {
|
|
385
403
|
await fs.access(agentsPath);
|
|
@@ -396,7 +414,7 @@ export class AgentSyncFs {
|
|
|
396
414
|
if (!entry.isDirectory()) continue;
|
|
397
415
|
|
|
398
416
|
const taskPath = path.join(agentsPath, entry.name);
|
|
399
|
-
|
|
417
|
+
|
|
400
418
|
try {
|
|
401
419
|
const stats = await fs.stat(taskPath);
|
|
402
420
|
const age = now - stats.mtimeMs;
|
|
@@ -449,11 +467,17 @@ export class AgentSyncFs {
|
|
|
449
467
|
// Remove old event listeners from the agent before resetting
|
|
450
468
|
if (this.agent) {
|
|
451
469
|
if (this.threadUpdateHandler) {
|
|
452
|
-
this.agent.agentEvents.removeListener(
|
|
470
|
+
this.agent.agentEvents.removeListener(
|
|
471
|
+
this.agent.eventTypes.threadUpdate,
|
|
472
|
+
this.threadUpdateHandler
|
|
473
|
+
);
|
|
453
474
|
this.threadUpdateHandler = undefined;
|
|
454
475
|
}
|
|
455
476
|
if (this.doneHandler) {
|
|
456
|
-
this.agent.agentEvents.removeListener(
|
|
477
|
+
this.agent.agentEvents.removeListener(
|
|
478
|
+
this.agent.eventTypes.done,
|
|
479
|
+
this.doneHandler
|
|
480
|
+
);
|
|
457
481
|
this.doneHandler = undefined;
|
|
458
482
|
}
|
|
459
483
|
this.agent = undefined;
|
|
@@ -144,6 +144,17 @@ export class KnowhowSimpleClient {
|
|
|
144
144
|
this.setJwt(jwt);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* Reload the JWT from disk (useful after login refreshes the token).
|
|
149
|
+
*/
|
|
150
|
+
refreshJwt() {
|
|
151
|
+
const freshJwt = loadKnowhowJwt();
|
|
152
|
+
if (freshJwt) {
|
|
153
|
+
this.setJwt(freshJwt);
|
|
154
|
+
this.jwtValidated = false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
147
158
|
setJwt(jwt: string) {
|
|
148
159
|
this.jwt = jwt;
|
|
149
160
|
this.headers = {
|
|
@@ -57,6 +57,12 @@ export class LazyToolsService extends ToolsService {
|
|
|
57
57
|
this.updateVisibleTools();
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// Override addTool (singular) to also route through allTools so that
|
|
61
|
+
// module-registered tools (via ModulesService.addTool) are tracked correctly.
|
|
62
|
+
addTool(tool: Tool) {
|
|
63
|
+
this.addTools([tool]);
|
|
64
|
+
}
|
|
65
|
+
|
|
60
66
|
// Override getTools to return only enabled tools
|
|
61
67
|
getTools() {
|
|
62
68
|
return this.tools; // Returns filtered subset
|
package/src/services/S3.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as fs from "fs";
|
|
2
|
-
import * as crypto from "crypto";
|
|
3
2
|
import { createWriteStream, createReadStream } from "fs";
|
|
4
3
|
import { pipeline, Readable } from "stream";
|
|
5
4
|
import * as util from "util";
|
|
@@ -14,17 +13,11 @@ export class S3Service {
|
|
|
14
13
|
try {
|
|
15
14
|
const fileContent = fs.readFileSync(filePath);
|
|
16
15
|
const fileStats = await fs.promises.stat(filePath);
|
|
17
|
-
const sha256Base64 = crypto
|
|
18
|
-
.createHash("sha256")
|
|
19
|
-
.update(fileContent)
|
|
20
|
-
.digest("base64");
|
|
21
16
|
|
|
22
17
|
const response = await fetch(presignedUrl, {
|
|
23
18
|
method: "PUT",
|
|
24
19
|
headers: {
|
|
25
20
|
"Content-Length": String(fileStats.size),
|
|
26
|
-
"x-amz-checksum-sha256": sha256Base64,
|
|
27
|
-
"x-amz-sdk-checksum-algorithm": "SHA256",
|
|
28
21
|
},
|
|
29
22
|
body: fileContent,
|
|
30
23
|
// @ts-ignore
|
|
@@ -5,11 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
import { Message } from "../clients/types";
|
|
7
7
|
import { EventService } from "./EventService";
|
|
8
|
-
import * as fs from "fs";
|
|
9
|
-
import * as fsPromises from "fs/promises";
|
|
10
|
-
import * as path from "path";
|
|
11
|
-
import { messagesToRenderEvents } from "../chat/renderer/messagesToRenderEvents";
|
|
12
|
-
import { KnowhowSimpleClient } from "./KnowhowClient";
|
|
13
8
|
|
|
14
9
|
export interface SyncedAgentWatcher {
|
|
15
10
|
/** Start watching for changes, emitting agent events */
|
|
@@ -27,7 +22,13 @@ export interface SyncedAgentWatcher {
|
|
|
27
22
|
/** EventService that emits agent lifecycle events (toolCall, toolUsed, agentSay, threadUpdate, done) */
|
|
28
23
|
agentEvents: EventService;
|
|
29
24
|
/** Event type constants mirroring BaseAgent.eventTypes */
|
|
30
|
-
eventTypes: {
|
|
25
|
+
eventTypes: {
|
|
26
|
+
done: string;
|
|
27
|
+
toolCall: string;
|
|
28
|
+
toolUsed: string;
|
|
29
|
+
agentSay: string;
|
|
30
|
+
threadUpdate: string;
|
|
31
|
+
};
|
|
31
32
|
/** Pause the remote agent */
|
|
32
33
|
pause(): Promise<void>;
|
|
33
34
|
/** Unpause/resume the remote agent */
|
|
@@ -44,7 +45,12 @@ export interface SyncedAgentWatcher {
|
|
|
44
45
|
export interface AttachableAgent {
|
|
45
46
|
name: string;
|
|
46
47
|
agentEvents: EventService;
|
|
47
|
-
eventTypes: {
|
|
48
|
+
eventTypes: {
|
|
49
|
+
done: string;
|
|
50
|
+
toolCall?: string;
|
|
51
|
+
toolUsed?: string;
|
|
52
|
+
agentSay?: string;
|
|
53
|
+
};
|
|
48
54
|
getTotalCostUsd(): number;
|
|
49
55
|
pause(): void | Promise<void>;
|
|
50
56
|
unpause(): void | Promise<void>;
|
|
@@ -104,294 +110,3 @@ export class WatcherBackedAgent implements AttachableAgent {
|
|
|
104
110
|
});
|
|
105
111
|
}
|
|
106
112
|
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Watches an agent running in another process via the filesystem.
|
|
110
|
-
* Reads .knowhow/processes/agents/<taskId>/metadata.json for changes.
|
|
111
|
-
* Sends messages by writing to .knowhow/processes/agents/<taskId>/input.txt
|
|
112
|
-
*/
|
|
113
|
-
export class FsSyncedAgentWatcher implements SyncedAgentWatcher {
|
|
114
|
-
public taskId: string = "";
|
|
115
|
-
private taskPath: string = "";
|
|
116
|
-
private watcher: fs.FSWatcher | null = null;
|
|
117
|
-
private lastThreadLength: number = 0;
|
|
118
|
-
public agentName: string = "unknown";
|
|
119
|
-
private debounceTimer: NodeJS.Timeout | null = null;
|
|
120
|
-
public agentEvents = new EventService();
|
|
121
|
-
public eventTypes = {
|
|
122
|
-
done: "done",
|
|
123
|
-
toolCall: "tool:pre_call",
|
|
124
|
-
toolUsed: "tool:post_call",
|
|
125
|
-
agentSay: "agent:say",
|
|
126
|
-
threadUpdate: "thread_update",
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
async startWatching(taskId: string): Promise<void> {
|
|
130
|
-
this.taskId = taskId;
|
|
131
|
-
this.taskPath = path.join(".knowhow/processes/agents", taskId);
|
|
132
|
-
|
|
133
|
-
// Load initial state to track current thread length (for delta rendering)
|
|
134
|
-
const metadata = await this.readMetadata();
|
|
135
|
-
if (metadata) {
|
|
136
|
-
const threads: any[][] = metadata.threads || [];
|
|
137
|
-
const lastThread = threads[threads.length - 1] || [];
|
|
138
|
-
this.agentName = metadata.agentName || taskId;
|
|
139
|
-
this.lastThreadLength = lastThread.length;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Watch the directory for metadata.json changes
|
|
143
|
-
try {
|
|
144
|
-
this.watcher = fs.watch(this.taskPath, (event, filename) => {
|
|
145
|
-
if (filename === "metadata.json" || filename === null) {
|
|
146
|
-
// Debounce rapid file writes
|
|
147
|
-
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
148
|
-
this.debounceTimer = setTimeout(() => {
|
|
149
|
-
this.onMetadataChanged().catch(() => {});
|
|
150
|
-
}, 200);
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
|
-
} catch (err: any) {
|
|
154
|
-
console.warn(`⚠️ Could not watch ${this.taskPath}: ${err.message}`);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
console.log(`👁️ Watching fs-synced agent: ${taskId} (${this.agentName})`);
|
|
158
|
-
console.log(
|
|
159
|
-
` Type /logs 20 to see recent messages, or type to send a message`
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
private async onMetadataChanged(): Promise<void> {
|
|
164
|
-
const metadata = await this.readMetadata();
|
|
165
|
-
if (!metadata?.threads) return;
|
|
166
|
-
|
|
167
|
-
const threads: any[][] = metadata.threads;
|
|
168
|
-
const lastThread = threads[threads.length - 1] || [];
|
|
169
|
-
|
|
170
|
-
// Only render NEW messages since last check
|
|
171
|
-
const newMessages = lastThread.slice(this.lastThreadLength);
|
|
172
|
-
if (newMessages.length > 0) {
|
|
173
|
-
const renderEvents = messagesToRenderEvents(
|
|
174
|
-
newMessages,
|
|
175
|
-
this.taskId,
|
|
176
|
-
this.agentName
|
|
177
|
-
);
|
|
178
|
-
for (const event of renderEvents) {
|
|
179
|
-
if (event.type === "toolCall") {
|
|
180
|
-
this.agentEvents.emit(this.eventTypes.toolCall, {
|
|
181
|
-
toolCall: (event as any).toolCall,
|
|
182
|
-
});
|
|
183
|
-
} else if (event.type === "toolResult") {
|
|
184
|
-
this.agentEvents.emit(this.eventTypes.toolUsed, {
|
|
185
|
-
toolCall: (event as any).toolCall,
|
|
186
|
-
functionResp: (event as any).result,
|
|
187
|
-
});
|
|
188
|
-
} else if (event.type === "agentMessage") {
|
|
189
|
-
this.agentEvents.emit(this.eventTypes.agentSay, {
|
|
190
|
-
message: (event as any).message,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
this.agentEvents.emit(this.eventTypes.threadUpdate, lastThread);
|
|
195
|
-
this.lastThreadLength = lastThread.length;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Emit done if the agent has completed and has a result
|
|
199
|
-
const status = metadata.status;
|
|
200
|
-
const result = metadata.result;
|
|
201
|
-
if ((status === "completed" || status === "killed") && result != null) {
|
|
202
|
-
this.stopWatching();
|
|
203
|
-
this.agentEvents.emit(this.eventTypes.done, result);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async sendMessage(message: string): Promise<void> {
|
|
208
|
-
const inputPath = path.join(this.taskPath, "input.txt");
|
|
209
|
-
await fsPromises.writeFile(inputPath, message, "utf8");
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
async getThreads(): Promise<any[][]> {
|
|
213
|
-
const metadata = await this.readMetadata();
|
|
214
|
-
return metadata?.threads || [];
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
stopWatching(): void {
|
|
218
|
-
if (this.debounceTimer) {
|
|
219
|
-
clearTimeout(this.debounceTimer);
|
|
220
|
-
this.debounceTimer = null;
|
|
221
|
-
}
|
|
222
|
-
this.watcher?.close();
|
|
223
|
-
this.watcher = null;
|
|
224
|
-
console.log(`🔌 Stopped watching agent: ${this.taskId}`);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async pause(): Promise<void> {
|
|
228
|
-
const statusPath = path.join(this.taskPath, "status.txt");
|
|
229
|
-
await fsPromises.writeFile(statusPath, "paused", "utf8");
|
|
230
|
-
console.log(`⏸️ Paused remote agent: ${this.taskId}`);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
async unpause(): Promise<void> {
|
|
234
|
-
const statusPath = path.join(this.taskPath, "status.txt");
|
|
235
|
-
await fsPromises.writeFile(statusPath, "running", "utf8");
|
|
236
|
-
console.log(`▶️ Unpaused remote agent: ${this.taskId}`);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
async kill(): Promise<void> {
|
|
240
|
-
const statusPath = path.join(this.taskPath, "status.txt");
|
|
241
|
-
await fsPromises.writeFile(statusPath, "killed", "utf8");
|
|
242
|
-
console.log(`🛑 Killed remote agent: ${this.taskId}`);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
private async readMetadata(): Promise<any> {
|
|
246
|
-
try {
|
|
247
|
-
const metaPath = path.join(this.taskPath, "metadata.json");
|
|
248
|
-
const content = await fsPromises.readFile(metaPath, "utf8");
|
|
249
|
-
return JSON.parse(content);
|
|
250
|
-
} catch {
|
|
251
|
-
return null;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Watches an agent running on Knowhow Web via polling the API.
|
|
258
|
-
* Polls GET /tasks/<taskId> every 3 seconds for thread updates.
|
|
259
|
-
* Sends messages via the client's sendMessageToAgent method.
|
|
260
|
-
*/
|
|
261
|
-
export class WebSyncedAgentWatcher implements SyncedAgentWatcher {
|
|
262
|
-
public taskId: string = "";
|
|
263
|
-
private client: KnowhowSimpleClient;
|
|
264
|
-
private pollInterval: NodeJS.Timeout | null = null;
|
|
265
|
-
private lastThreadLength: number = 0;
|
|
266
|
-
public agentName: string = "remote-agent";
|
|
267
|
-
private stopped: boolean = false;
|
|
268
|
-
public agentEvents = new EventService();
|
|
269
|
-
public eventTypes = {
|
|
270
|
-
done: "done",
|
|
271
|
-
toolCall: "tool:pre_call",
|
|
272
|
-
toolUsed: "tool:post_call",
|
|
273
|
-
agentSay: "agent:say",
|
|
274
|
-
threadUpdate: "thread_update",
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
constructor(client?: KnowhowSimpleClient) {
|
|
278
|
-
this.client = client || new KnowhowSimpleClient();
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
async startWatching(taskId: string): Promise<void> {
|
|
282
|
-
this.taskId = taskId;
|
|
283
|
-
this.stopped = false;
|
|
284
|
-
|
|
285
|
-
// Load initial state to track current thread length
|
|
286
|
-
try {
|
|
287
|
-
const details = await this.client.getTaskDetails(taskId);
|
|
288
|
-
const threads: any[][] = details?.data?.threads || [];
|
|
289
|
-
const lastThread = threads[threads.length - 1] || [];
|
|
290
|
-
this.agentName = "remote-agent";
|
|
291
|
-
this.lastThreadLength = lastThread.length;
|
|
292
|
-
} catch (err: any) {
|
|
293
|
-
console.warn(
|
|
294
|
-
`⚠️ Could not load initial state for task ${taskId}: ${err.message}`
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Poll every 3 seconds for updates
|
|
299
|
-
this.pollInterval = setInterval(async () => {
|
|
300
|
-
if (!this.stopped) {
|
|
301
|
-
await this.onPoll().catch(() => {});
|
|
302
|
-
}
|
|
303
|
-
}, 3000);
|
|
304
|
-
|
|
305
|
-
console.log(`🌐 Watching web-synced agent: ${taskId} (${this.agentName})`);
|
|
306
|
-
console.log(
|
|
307
|
-
` Type /logs 20 to see recent messages, or type to send a message`
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
private async onPoll(): Promise<void> {
|
|
312
|
-
if (this.stopped) return;
|
|
313
|
-
try {
|
|
314
|
-
const details = await this.client.getTaskDetails(this.taskId);
|
|
315
|
-
const threads: any[][] = details?.data?.threads || [];
|
|
316
|
-
const lastThread = threads[threads.length - 1] || [];
|
|
317
|
-
|
|
318
|
-
const newMessages = lastThread.slice(this.lastThreadLength);
|
|
319
|
-
if (newMessages.length > 0) {
|
|
320
|
-
const renderEvents = messagesToRenderEvents(
|
|
321
|
-
newMessages,
|
|
322
|
-
this.taskId,
|
|
323
|
-
this.agentName
|
|
324
|
-
);
|
|
325
|
-
for (const event of renderEvents) {
|
|
326
|
-
if (event.type === "toolCall") {
|
|
327
|
-
this.agentEvents.emit(this.eventTypes.toolCall, {
|
|
328
|
-
toolCall: (event as any).toolCall,
|
|
329
|
-
});
|
|
330
|
-
} else if (event.type === "toolResult") {
|
|
331
|
-
this.agentEvents.emit(this.eventTypes.toolUsed, {
|
|
332
|
-
toolCall: (event as any).toolCall,
|
|
333
|
-
functionResp: (event as any).result,
|
|
334
|
-
});
|
|
335
|
-
} else if (event.type === "agentMessage") {
|
|
336
|
-
this.agentEvents.emit(this.eventTypes.agentSay, {
|
|
337
|
-
message: (event as any).message,
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
this.agentEvents.emit(this.eventTypes.threadUpdate, lastThread);
|
|
342
|
-
this.lastThreadLength = lastThread.length;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Stop polling and emit done if task is complete with a result
|
|
346
|
-
const status = details?.data?.status;
|
|
347
|
-
const result = details?.data?.result;
|
|
348
|
-
if (status === "completed" || status === "killed") {
|
|
349
|
-
this.stopWatching();
|
|
350
|
-
if (result != null) {
|
|
351
|
-
this.agentEvents.emit(this.eventTypes.done, result);
|
|
352
|
-
} else {
|
|
353
|
-
console.log(`\n✅ Remote agent ${this.taskId} status: ${status} (no result)`);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
} catch {
|
|
357
|
-
// Silently continue on poll errors
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
async sendMessage(message: string): Promise<void> {
|
|
362
|
-
await this.client.sendMessageToAgent(this.taskId, message);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
async getThreads(): Promise<any[][]> {
|
|
366
|
-
try {
|
|
367
|
-
const details = await this.client.getTaskDetails(this.taskId);
|
|
368
|
-
return details?.data?.threads || [];
|
|
369
|
-
} catch {
|
|
370
|
-
return [];
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
stopWatching(): void {
|
|
375
|
-
this.stopped = true;
|
|
376
|
-
if (this.pollInterval) {
|
|
377
|
-
clearInterval(this.pollInterval);
|
|
378
|
-
this.pollInterval = null;
|
|
379
|
-
}
|
|
380
|
-
console.log(`🔌 Stopped watching web agent: ${this.taskId}`);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
async pause(): Promise<void> {
|
|
384
|
-
await this.client.pauseAgent(this.taskId);
|
|
385
|
-
console.log(`⏸️ Paused remote web agent: ${this.taskId}`);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
async unpause(): Promise<void> {
|
|
389
|
-
await this.client.resumeAgent(this.taskId);
|
|
390
|
-
console.log(`▶️ Unpaused remote web agent: ${this.taskId}`);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
async kill(): Promise<void> {
|
|
394
|
-
await this.client.killAgent(this.taskId);
|
|
395
|
-
console.log(`🛑 Killed remote web agent: ${this.taskId}`);
|
|
396
|
-
}
|
|
397
|
-
}
|
package/src/services/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { getConfig, getGlobalConfig } from "../../config";
|
|
|
2
2
|
import { KnowhowModule, ModuleContext } from "./types";
|
|
3
3
|
import { ToolsService } from "../Tools";
|
|
4
4
|
import { services } from "../";
|
|
5
|
-
import
|
|
5
|
+
import * as path from "path";
|
|
6
6
|
|
|
7
7
|
export class ModulesService {
|
|
8
8
|
async loadModulesFromConfig(context?: ModuleContext) {
|
|
@@ -35,8 +35,17 @@ export class ModulesService {
|
|
|
35
35
|
];
|
|
36
36
|
|
|
37
37
|
for (const modulePath of allModulePaths) {
|
|
38
|
-
|
|
38
|
+
// Resolve relative paths relative to process.cwd() so that paths like
|
|
39
|
+
// "../../packages/knowhow-module-load-webpage" in knowhow.json work
|
|
40
|
+
// regardless of where the compiled output lives.
|
|
41
|
+
const resolvedPath = modulePath.startsWith(".")
|
|
42
|
+
? path.resolve(process.cwd(), modulePath)
|
|
43
|
+
: modulePath;
|
|
44
|
+
const rawModule = require(resolvedPath);
|
|
45
|
+
const importedModule = (rawModule.default || rawModule) as KnowhowModule;
|
|
46
|
+
console.log(`🔌 Loading module: ${modulePath} (resolved: ${resolvedPath})`);
|
|
39
47
|
await importedModule.init({ config, cwd: process.cwd(), context });
|
|
48
|
+
console.log(`✅ Module initialized: ${modulePath} (tools: ${importedModule.tools.length}, agents: ${importedModule.agents.length}, plugins: ${importedModule.plugins.length}, clients: ${importedModule.clients.length})`);
|
|
40
49
|
|
|
41
50
|
for (const agent of importedModule.agents) {
|
|
42
51
|
agentService.registerAgent(agent);
|