mirror of
https://github.com/hanzoai/chat.git
synced 2026-09-30 20:51:17 +00:00
Measured rather than guessed: 186 suites, 69 failing, and TWELVE of those failed
during import having executed zero tests. That distinction is invisible in a
failed/total count and it matters — a suite that runs and fails tells you
something, a suite that dies at import tells you only that somebody wrote a file.
Same cause throughout, and it cascades: the spec replaces a `@hanzochat/*`
package with the two or three names it expects the subject to want, so the first
thing deeper in the require graph that wants a fourth throws. One file went
through five in a row. Spreading `jest.requireActual` under the overrides fixes
it at the root; `deleteUser` additionally overrode `CacheKeys` with `{}`, which
made the real cacheConfig reject every namespace it was asked to validate.
deleteUser 7 tests modelEndHandler 6 tests
preview 15 tests addedConvo 3 tests
process 49 tests
All red, and left that way — they are upstream specs whose implementations did
not land, and a red suite that runs is worth more than a green name that does
not. Six remain dead (roles, abort, streamTenant, auth.cloudfront,
imageTools-agent, importers); their blockers are middleware shapes rather than
package stubs. Nothing here gates.
Co-authored-by: Hanzo Dev <[email protected]>
111 lines
3.7 KiB
JavaScript
111 lines
3.7 KiB
JavaScript
const mockInitializeAgent = jest.fn();
|
|
const mockValidateAgentModel = jest.fn();
|
|
const mockLoadAddedAgent = jest.fn();
|
|
const mockGetAgent = jest.fn();
|
|
const mockGetMCPServerTools = jest.fn();
|
|
|
|
jest.mock('@hanzochat/data-schemas', () => ({
|
|
...jest.requireActual('@hanzochat/data-schemas'),
|
|
logger: {
|
|
debug: jest.fn(),
|
|
info: jest.fn(),
|
|
warn: jest.fn(),
|
|
error: jest.fn(),
|
|
},
|
|
}));
|
|
|
|
jest.mock('@hanzochat/api', () => ({
|
|
...jest.requireActual('@hanzochat/api'),
|
|
ADDED_AGENT_ID: '__added_agent__',
|
|
initializeAgent: (...args) => mockInitializeAgent(...args),
|
|
validateAgentModel: (...args) => mockValidateAgentModel(...args),
|
|
loadAddedAgent: (params) => mockLoadAddedAgent(params),
|
|
}));
|
|
|
|
jest.mock('~/server/services/Files/permissions', () => ({
|
|
filterFilesByAgentAccess: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('~/server/services/Config', () => ({
|
|
getMCPServerTools: (...args) => mockGetMCPServerTools(...args),
|
|
}));
|
|
|
|
jest.mock('~/models', () => ({
|
|
getAgent: (...args) => mockGetAgent(...args),
|
|
}));
|
|
|
|
const { processAddedConvo } = require('./addedConvo');
|
|
|
|
const makeReq = () => ({ user: { id: 'u1', role: 'USER' } });
|
|
|
|
/**
|
|
* Phase 8 pins `processAddedConvo` forwarding the run's `codeEnvAvailable` to
|
|
* the added-convo `initializeAgent` call. Without this, parallel multi-convo
|
|
* agents with `tools: ['execute_code']` silently drop `bash_tool` + `read_file`
|
|
* even though the primary had them — pre-Phase-8 the legacy
|
|
* `CodeExecutionToolDefinition` landed in their `toolDefinitions` via the
|
|
* registry regardless of any explicit flag.
|
|
*/
|
|
describe('processAddedConvo — codeEnvAvailable passthrough', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
mockValidateAgentModel.mockResolvedValue({ isValid: true });
|
|
mockInitializeAgent.mockResolvedValue({
|
|
id: 'added-agent',
|
|
userMCPAuthMap: undefined,
|
|
});
|
|
mockLoadAddedAgent.mockResolvedValue({ id: 'added-agent', provider: 'openai' });
|
|
});
|
|
|
|
const baseParams = (overrides = {}) => ({
|
|
req: makeReq(),
|
|
res: {},
|
|
endpointOption: { addedConvo: { model: 'gpt-4o', agent_id: 'added-agent' } },
|
|
modelsConfig: { openai: ['gpt-4o'] },
|
|
logViolation: jest.fn(),
|
|
loadTools: jest.fn(),
|
|
requestFiles: [],
|
|
conversationId: 'conv-1',
|
|
parentMessageId: null,
|
|
allowedProviders: new Set(['openai']),
|
|
agentConfigs: new Map(),
|
|
primaryAgentId: 'primary-id',
|
|
primaryAgent: { id: 'primary-id' },
|
|
userMCPAuthMap: undefined,
|
|
...overrides,
|
|
});
|
|
|
|
it('forwards codeEnvAvailable=true to the added-convo initializeAgent call', async () => {
|
|
await processAddedConvo(baseParams({ codeEnvAvailable: true }));
|
|
|
|
expect(mockInitializeAgent).toHaveBeenCalledWith(
|
|
expect.objectContaining({ codeEnvAvailable: true }),
|
|
expect.anything(),
|
|
);
|
|
});
|
|
|
|
it('forwards codeEnvAvailable=false verbatim (not coerced to undefined)', async () => {
|
|
/* Symmetric coverage: if the runtime gate is off for the primary, the
|
|
parallel agent must not accidentally re-enable code execution via a
|
|
defaulting bug in the destructuring. */
|
|
await processAddedConvo(baseParams({ codeEnvAvailable: false }));
|
|
|
|
expect(mockInitializeAgent).toHaveBeenCalledWith(
|
|
expect.objectContaining({ codeEnvAvailable: false }),
|
|
expect.anything(),
|
|
);
|
|
});
|
|
|
|
it('forwards codeEnvAvailable=undefined when caller omits it (no silent default)', async () => {
|
|
/* Backstop for the "caller didn't update after Phase 8" case — the
|
|
added-convo path must not invent a truthy value out of thin air.
|
|
Matches `initializeAgent`'s own "explicit opt-in" semantics. */
|
|
await processAddedConvo(baseParams());
|
|
|
|
expect(mockInitializeAgent).toHaveBeenCalledWith(
|
|
expect.objectContaining({ codeEnvAvailable: undefined }),
|
|
expect.anything(),
|
|
);
|
|
});
|
|
});
|