mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2026-01-13 04:41:32 -08:00
test: fix
This commit is contained in:
parent
7dfda0e12d
commit
31e24de58e
4 changed files with 31 additions and 48 deletions
|
|
@ -161,3 +161,25 @@ const esbuild = require('esbuild');
|
|||
```
|
||||
|
||||
If tried to add this to `esbuildLoaderRule` will cause this error. The object contains an internal reference chain (`.default.default`) that triggers recursion when webpack-merge/clone-deep attempts to merge it.
|
||||
|
||||
## Error: Can't resolve 'os' in
|
||||
|
||||
```log
|
||||
@ ./src/services/libs/i18n/i18next-electron-fs-backend.ts 3:0-44 147:10-22 172:10-22
|
||||
@ ./src/services/libs/i18n/renderer.ts 4:0-77 8:20-37
|
||||
@ ./src/renderer.tsx 20:0-65 36:5-21
|
||||
|
||||
ERROR in ./node_modules/winston/dist/winston/transports/stream.js 26:9-22
|
||||
Module not found: Error: Can't resolve 'os' in 'C:\Users\linonetwo\Documents\repo-c\TidGi-Desktop\node_modules\winston\dist\winston\transports'
|
||||
|
||||
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
|
||||
This is no longer the case. Verify if you need this module and configure a polyfill for it.
|
||||
|
||||
If you want to include a polyfill, you need to:
|
||||
- add a fallback 'resolve.fallback: { "os": require.resolve("os-browserify/browser") }'
|
||||
- install 'os-browserify'
|
||||
If you don't want to include a polyfill, you can use an empty module like this:
|
||||
resolve.fallback: { "os": false }
|
||||
```
|
||||
|
||||
Usually because you import the server-side `logger` in renderer process code. You have to use `console` or add new transport in [rendererTransport.ts](src/services/libs/log/rendererTransport.ts).
|
||||
|
|
|
|||
|
|
@ -142,23 +142,21 @@ Feature: Agent Workflow - Tool Usage and Multi-Round Conversation
|
|||
When I click on a "message input textarea" element with selector "[data-testid='agent-message-input']"
|
||||
When I type "在 wiki 里创建一个新笔记,内容为 test" in "chat input" element with selector "[data-testid='agent-message-input']"
|
||||
And I press "Enter" key
|
||||
And I wait for 1 seconds
|
||||
And I wait for 0.2 seconds
|
||||
And I should see a "user message" element with selector "*:has-text('在 wiki 里创建一个新笔记,内容为 test')"
|
||||
And I should see a "tool use indicator" element with selector "*:has-text('tool_use')"
|
||||
And I should see a "wiki operation tool" element with selector "*:has-text('wiki-operation')"
|
||||
And I wait for 2 seconds
|
||||
And I wait for 0.2 seconds
|
||||
And I should see a "function result error" element with selector "*:has-text('functions_result')"
|
||||
And I should see a "workspace not found" element with selector "*:has-text('Workspace with name or ID \"default\" does not exist')"
|
||||
|
||||
# Second round: assistant suggests wiki workspace and operation succeeds (automated by assistant/tool)
|
||||
And I wait for 2 seconds
|
||||
And I wait for 0.2 seconds
|
||||
And I should see a "assistant suggestion" element with selector "*:has-text('tool_use')"
|
||||
And I should see a "tool use indicator" element with selector "*:has-text('tool_use')"
|
||||
And I should see a "wiki operation tool" element with selector "*:has-text('wiki-operation')"
|
||||
And I wait for 2 seconds
|
||||
And I wait for 0.2 seconds
|
||||
And I should see a "function result success" element with selector "*:has-text('functions_result')"
|
||||
And I wait for 5 seconds
|
||||
And I should see a "success message" element with selector "*:has-text('Successfully added tiddler')"
|
||||
And I wait for 2 seconds
|
||||
And I wait for 0.2 seconds
|
||||
And I should see a "assistant confirmation" element with selector "*:has-text('已成功在工作区 wiki 中创建条目')"
|
||||
Then I should see 6 messages in chat history
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { logger } from '@services/libs/log';
|
||||
import { createServer, IncomingMessage, Server, ServerResponse } from 'http';
|
||||
import { AddressInfo } from 'net';
|
||||
|
||||
|
|
@ -143,27 +142,13 @@ export class MockOpenAIServer {
|
|||
|
||||
private generateChatCompletionResponse(chatRequest: ChatRequest) {
|
||||
const modelName = chatRequest.model || 'test-model';
|
||||
|
||||
// Increment call count for each API request
|
||||
this.callCount++;
|
||||
|
||||
logger.debug('[mockOpenAI] generateChatCompletionResponse', {
|
||||
modelName,
|
||||
callCount: this.callCount,
|
||||
totalMessages: chatRequest.messages.length,
|
||||
});
|
||||
logger.debug('mockOpenAI message types', {
|
||||
messageTypes: chatRequest.messages.map((m) =>
|
||||
`${m.role}:${String(m.content).includes('<functions_result>') ? 'FUNCTIONS_RESULT' : String(m.content).substring(0, 30) + '...'}`
|
||||
),
|
||||
});
|
||||
|
||||
// Use call count to determine which response to return (1-indexed)
|
||||
const ruleIndex = this.callCount - 1;
|
||||
const responseRule = this.rules[ruleIndex];
|
||||
|
||||
if (!responseRule) {
|
||||
logger.debug('[mockOpenAI] No more responses available for call', { callCount: this.callCount });
|
||||
return {
|
||||
id: 'chatcmpl-test-' + Date.now().toString(),
|
||||
object: 'chat.completion',
|
||||
|
|
@ -174,8 +159,6 @@ export class MockOpenAIServer {
|
|||
};
|
||||
}
|
||||
|
||||
logger.debug('[mockOpenAI] Using rule for call', { callCount: this.callCount, preview: responseRule.response.substring(0, 100) + '...' });
|
||||
|
||||
return {
|
||||
id: 'chatcmpl-test-' + Date.now().toString(),
|
||||
object: 'chat.completion',
|
||||
|
|
@ -199,20 +182,12 @@ export class MockOpenAIServer {
|
|||
if (response.writableEnded) return;
|
||||
|
||||
const modelName = chatRequest.model || 'test-model';
|
||||
|
||||
// Increment call count for streaming requests too
|
||||
this.callCount++;
|
||||
|
||||
// Use call count to determine which response to return (1-indexed)
|
||||
const ruleIndex = this.callCount - 1;
|
||||
const responseRule = this.rules[ruleIndex];
|
||||
|
||||
logger.debug('mockOpenAI streaming check', {
|
||||
modelName,
|
||||
callCount: this.callCount,
|
||||
matched: !!responseRule,
|
||||
});
|
||||
|
||||
// If matched: honor client's stream request. If client requests stream, always stream the matched.response.
|
||||
if (responseRule && chatRequest.stream) {
|
||||
response.setHeader('Content-Type', 'text/plain; charset=utf-8');
|
||||
|
|
@ -268,26 +243,16 @@ export class MockOpenAIServer {
|
|||
const roleLine = `data: ${JSON.stringify(roleChunk)}\n\n`;
|
||||
const contentLine = `data: ${JSON.stringify(contentChunk)}\n\n`;
|
||||
const finalLine = `data: ${JSON.stringify(finalChunk)}\n\n`;
|
||||
|
||||
logger.debug('mockOpenAI sending streaming chunks', {
|
||||
responseContentPreview: responseRule.response.substring(0, 200),
|
||||
role: roleLine.substring(0, 100) + '...',
|
||||
contentPreview: contentLine.substring(0, 200) + '...',
|
||||
finalPreview: finalLine.substring(0, 100) + '...',
|
||||
});
|
||||
|
||||
response.write(roleLine);
|
||||
response.write(contentLine);
|
||||
response.write(finalLine);
|
||||
response.write('data: [DONE]\n\n');
|
||||
logger.debug('mockOpenAI stream finished', { callCount: this.callCount });
|
||||
response.end();
|
||||
return;
|
||||
}
|
||||
|
||||
// If matched but client did not request stream, return a regular JSON chat completion
|
||||
if (responseRule && !chatRequest.stream) {
|
||||
logger.debug('[mockOpenAI] Using non-stream rule for call', { callCount: this.callCount, preview: responseRule.response.substring(0, 100) + '...' });
|
||||
const resp = {
|
||||
id: 'chatcmpl-test-' + Date.now().toString(),
|
||||
object: 'chat.completion',
|
||||
|
|
@ -305,7 +270,6 @@ export class MockOpenAIServer {
|
|||
],
|
||||
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
||||
};
|
||||
|
||||
if (!response.writableEnded) {
|
||||
response.setHeader('Content-Type', 'application/json');
|
||||
response.writeHead(200);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { I18NChannels } from '@/constants/channels';
|
||||
import { logger } from '@services/libs/log';
|
||||
import type { BackendModule, InitOptions, MultiReadCallback, ReadCallback, Services } from 'i18next';
|
||||
import { cloneDeep, merge, Object } from 'lodash';
|
||||
|
||||
|
|
@ -188,7 +187,7 @@ export class Backend implements BackendModule {
|
|||
// }
|
||||
const { keys } = payload;
|
||||
if (!keys) return;
|
||||
for (const key of keys) {
|
||||
for (const key of keys) {
|
||||
// Write methods don't have any callbacks from what I've seen,
|
||||
// so this is called more than I thought; but necessary!
|
||||
const entry = this.writeCallbacks[key];
|
||||
|
|
@ -217,7 +216,7 @@ export class Backend implements BackendModule {
|
|||
for (const element of toWork as Array<{ key: string; values: Array<{ key: string; fallbackValue: string; callback?: (error?: unknown) => void }> }>) {
|
||||
const anonymous = (error: unknown, data: unknown) => {
|
||||
if (error) {
|
||||
logger.error(`${this.rendererLog} encountered error when trying to read file '${element.key}' before writing missing translation`, { error });
|
||||
console.error(`${this.rendererLog} encountered error when trying to read file '${element.key}' before writing missing translation`, { error });
|
||||
return;
|
||||
}
|
||||
const keySeparator = Boolean(this.i18nextOptions.keySeparator); // Do we have a key separator or not?
|
||||
|
|
@ -245,7 +244,7 @@ export class Backend implements BackendModule {
|
|||
}
|
||||
// Send out the message to the ipcMain process
|
||||
if (debug) {
|
||||
logger.debug(`${this.rendererLog} requesting the missing key '${String(writeKeys)}' be written to file '${element.key}'.`);
|
||||
console.debug(`${this.rendererLog} requesting the missing key '${String(writeKeys)}' be written to file '${element.key}'.`);
|
||||
}
|
||||
i18nextElectronBackend.send(I18NChannels.writeFileRequest, {
|
||||
keys: writeKeys,
|
||||
|
|
@ -280,7 +279,7 @@ export class Backend implements BackendModule {
|
|||
|
||||
// Reads a given translation file
|
||||
read(language: string, namespace: string, callback: ReadCallback) {
|
||||
const loadPathString = String(this.backendOptions.loadPath ?? defaultOptions.loadPath);
|
||||
const loadPathString = String(this.backendOptions.loadPath ?? defaultOptions.loadPath);
|
||||
const filename = safeInterpolate(this.services.interpolator, loadPathString, { lng: language, ns: namespace });
|
||||
this.requestFileRead(filename, (error?: unknown, data?: unknown) => {
|
||||
type ReadCallbackParameters = Parameters<ReadCallback>;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue