@futdevpro/nts-dynamo 1.15.105 → 1.15.107
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/.dynamo/logs/cicd-pipeline/output.log +1805 -1863
- package/.dynamo/logs/cicd-pipeline/status.json +28 -28
- package/build/_modules/ai/_collections/ai-model-config-validator.util.d.ts +32 -0
- package/build/_modules/ai/_collections/ai-model-config-validator.util.d.ts.map +1 -0
- package/build/_modules/ai/_collections/ai-model-config-validator.util.js +95 -0
- package/build/_modules/ai/_collections/ai-model-config-validator.util.js.map +1 -0
- package/build/_modules/ai/_collections/ai-provider-error.util.d.ts +35 -0
- package/build/_modules/ai/_collections/ai-provider-error.util.d.ts.map +1 -0
- package/build/_modules/ai/_collections/ai-provider-error.util.js +82 -0
- package/build/_modules/ai/_collections/ai-provider-error.util.js.map +1 -0
- package/build/_modules/ai/_models/interfaces/dynts-ai-provider-error.interface.d.ts +17 -0
- package/build/_modules/ai/_models/interfaces/dynts-ai-provider-error.interface.d.ts.map +1 -0
- package/build/_modules/ai/_models/interfaces/dynts-ai-provider-error.interface.js +3 -0
- package/build/_modules/ai/_models/interfaces/dynts-ai-provider-error.interface.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-default-collection.util.d.ts +23 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-default-collection.util.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-default-collection.util.js +52 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-default-collection.util.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-fixture-match.util.d.ts +34 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-fixture-match.util.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-fixture-match.util.js +56 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-fixture-match.util.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-fixture-serializer.util.d.ts +33 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-fixture-serializer.util.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-fixture-serializer.util.js +89 -0
- package/build/_modules/ai/_modules/ai-mock/_collections/aim-fixture-serializer.util.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_enums/aim-modality.enum.d.ts +16 -0
- package/build/_modules/ai/_modules/ai-mock/_enums/aim-modality.enum.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_enums/aim-modality.enum.js +20 -0
- package/build/_modules/ai/_modules/ai-mock/_enums/aim-modality.enum.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-call-input.interface.d.ts +15 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-call-input.interface.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-call-input.interface.js +3 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-call-input.interface.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-error.interface.d.ts +11 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-error.interface.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-error.interface.js +3 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-error.interface.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-fixture.interface.d.ts +30 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-fixture.interface.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-fixture.interface.js +3 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-fixture.interface.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-request.interface.d.ts +19 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-request.interface.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-request.interface.js +3 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-request.interface.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-service-collection.interface.d.ts +19 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-service-collection.interface.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-service-collection.interface.js +3 -0
- package/build/_modules/ai/_modules/ai-mock/_models/interfaces/aim-service-collection.interface.js.map +1 -0
- package/build/_modules/ai/{_services → _modules/ai-mock/_services}/ai-embedding-mock.service.d.ts +2 -2
- package/build/_modules/ai/_modules/ai-mock/_services/ai-embedding-mock.service.d.ts.map +1 -0
- package/build/_modules/ai/{_services → _modules/ai-mock/_services}/ai-embedding-mock.service.js +1 -1
- package/build/_modules/ai/_modules/ai-mock/_services/ai-embedding-mock.service.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-fixture-harness.service.d.ts +48 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-fixture-harness.service.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-fixture-harness.service.js +104 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-fixture-harness.service.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-fixture-store.service.d.ts +35 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-fixture-store.service.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-fixture-store.service.js +60 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-fixture-store.service.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-mock.service.d.ts +60 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-mock.service.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-mock.service.js +121 -0
- package/build/_modules/ai/_modules/ai-mock/_services/aim-mock.service.js.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/index.d.ts +14 -0
- package/build/_modules/ai/_modules/ai-mock/index.d.ts.map +1 -0
- package/build/_modules/ai/_modules/ai-mock/index.js +41 -0
- package/build/_modules/ai/_modules/ai-mock/index.js.map +1 -0
- package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.d.ts +18 -0
- package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.d.ts.map +1 -1
- package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.js +58 -30
- package/build/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.js.map +1 -1
- package/build/_modules/ai/_services/ai-embedding-provider.registry.d.ts +1 -1
- package/build/_modules/ai/_services/ai-embedding-provider.registry.d.ts.map +1 -1
- package/build/_modules/ai/_services/ai-embedding-provider.registry.js +1 -1
- package/build/_modules/ai/_services/ai-embedding-provider.registry.js.map +1 -1
- package/build/_modules/ai/_services/ai-llm.service-base.d.ts +16 -0
- package/build/_modules/ai/_services/ai-llm.service-base.d.ts.map +1 -1
- package/build/_modules/ai/_services/ai-llm.service-base.js +65 -0
- package/build/_modules/ai/_services/ai-llm.service-base.js.map +1 -1
- package/build/_modules/ai/index.d.ts +4 -1
- package/build/_modules/ai/index.d.ts.map +1 -1
- package/build/_modules/ai/index.js +9 -1
- package/build/_modules/ai/index.js.map +1 -1
- package/package.json +11 -2
- package/src/_modules/ai/_collections/ai-model-config-validator.util.spec.ts +150 -0
- package/src/_modules/ai/_collections/ai-model-config-validator.util.ts +131 -0
- package/src/_modules/ai/_collections/ai-provider-error.util.ts +98 -0
- package/src/_modules/ai/_models/interfaces/dynts-ai-provider-error.interface.ts +16 -0
- package/src/_modules/ai/_modules/ai-mock/_collections/aim-default-collection.util.spec.ts +72 -0
- package/src/_modules/ai/_modules/ai-mock/_collections/aim-default-collection.util.ts +71 -0
- package/src/_modules/ai/_modules/ai-mock/_collections/aim-fixture-match.util.spec.ts +57 -0
- package/src/_modules/ai/_modules/ai-mock/_collections/aim-fixture-match.util.ts +60 -0
- package/src/_modules/ai/_modules/ai-mock/_collections/aim-fixture-serializer.util.spec.ts +56 -0
- package/src/_modules/ai/_modules/ai-mock/_collections/aim-fixture-serializer.util.ts +107 -0
- package/src/_modules/ai/_modules/ai-mock/_enums/aim-modality.enum.ts +15 -0
- package/src/_modules/ai/_modules/ai-mock/_models/interfaces/aim-call-input.interface.ts +14 -0
- package/src/_modules/ai/_modules/ai-mock/_models/interfaces/aim-error.interface.ts +11 -0
- package/src/_modules/ai/_modules/ai-mock/_models/interfaces/aim-fixture.interface.ts +30 -0
- package/src/_modules/ai/_modules/ai-mock/_models/interfaces/aim-request.interface.ts +19 -0
- package/src/_modules/ai/_modules/ai-mock/_models/interfaces/aim-service-collection.interface.ts +20 -0
- package/src/_modules/ai/{_services → _modules/ai-mock/_services}/ai-embedding-mock.service.spec.ts +1 -1
- package/src/_modules/ai/{_services → _modules/ai-mock/_services}/ai-embedding-mock.service.ts +2 -2
- package/src/_modules/ai/_modules/ai-mock/_services/aim-fixture-harness.service.spec.ts +134 -0
- package/src/_modules/ai/_modules/ai-mock/_services/aim-fixture-harness.service.ts +127 -0
- package/src/_modules/ai/_modules/ai-mock/_services/aim-fixture-pipeline.spec.ts +105 -0
- package/src/_modules/ai/_modules/ai-mock/_services/aim-fixture-store.service.spec.ts +50 -0
- package/src/_modules/ai/_modules/ai-mock/_services/aim-fixture-store.service.ts +65 -0
- package/src/_modules/ai/_modules/ai-mock/_services/aim-mock.service.spec.ts +112 -0
- package/src/_modules/ai/_modules/ai-mock/_services/aim-mock.service.ts +142 -0
- package/src/_modules/ai/_modules/ai-mock/index.ts +44 -0
- package/src/_modules/ai/_modules/open-ai/_services/oai-llm.service-base.ts +77 -35
- package/src/_modules/ai/_services/ai-embedding-provider.registry.spec.ts +1 -1
- package/src/_modules/ai/_services/ai-embedding-provider.registry.ts +1 -1
- package/src/_modules/ai/_services/ai-llm.service-base.reconciler.spec.ts +133 -0
- package/src/_modules/ai/_services/ai-llm.service-base.ts +80 -0
- package/src/_modules/ai/index.ts +11 -1
- package/build/_modules/ai/_services/ai-embedding-mock.service.d.ts.map +0 -1
- package/build/_modules/ai/_services/ai-embedding-mock.service.js.map +0 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { DyFM_Error } from '@futdevpro/fsm-dynamo';
|
|
2
|
+
import { DyFM_AI_ModelInfo, DyFM_AI_ModelType, DyFM_AI_Provider } from '@futdevpro/fsm-dynamo/ai';
|
|
3
|
+
|
|
4
|
+
import { DyNTS_AIMock_Modality } from '../_enums/aim-modality.enum';
|
|
5
|
+
import { DyNTS_AIMock_Request } from '../_models/interfaces/aim-request.interface';
|
|
6
|
+
import { DyNTS_AIMock_Fixture } from '../_models/interfaces/aim-fixture.interface';
|
|
7
|
+
import { DyNTS_AIMock_FixtureHarness_Service } from './aim-fixture-harness.service';
|
|
8
|
+
|
|
9
|
+
describe('| DyNTS_AIMock_FixtureHarness_Service (MP-3 SP-3.2)', () => {
|
|
10
|
+
|
|
11
|
+
const registry: DyFM_AI_ModelInfo[] = [
|
|
12
|
+
{
|
|
13
|
+
id: 'cheap-mini',
|
|
14
|
+
provider: DyFM_AI_Provider.OpenAI,
|
|
15
|
+
modelType: DyFM_AI_ModelType.Chat,
|
|
16
|
+
tier: 'mini',
|
|
17
|
+
capabilities: {} as any,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'expensive-pro',
|
|
21
|
+
provider: DyFM_AI_Provider.OpenAI,
|
|
22
|
+
modelType: DyFM_AI_ModelType.Chat,
|
|
23
|
+
tier: 'pro',
|
|
24
|
+
capabilities: {} as any,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'expensive-opus',
|
|
28
|
+
provider: DyFM_AI_Provider.Anthropic,
|
|
29
|
+
modelType: DyFM_AI_ModelType.Chat,
|
|
30
|
+
tier: 'Opus',
|
|
31
|
+
capabilities: {} as any,
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
/** Stub-generator, ami JELZI, ha meghivtak — igy bizonyithato, hogy a zarak MEG a hivas elott fognak. */
|
|
36
|
+
function makeStub(): { calls: number, generate: (request: DyNTS_AIMock_Request) => Promise<unknown> } {
|
|
37
|
+
const state: { calls: number, generate: (request: DyNTS_AIMock_Request) => Promise<unknown> } = {
|
|
38
|
+
calls: 0,
|
|
39
|
+
generate: async (): Promise<unknown> => {
|
|
40
|
+
state.calls++;
|
|
41
|
+
|
|
42
|
+
return 'generated-output';
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return state;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function request(model: string): DyNTS_AIMock_Request {
|
|
50
|
+
return {
|
|
51
|
+
provider: 'open-ai',
|
|
52
|
+
model: model,
|
|
53
|
+
modality: DyNTS_AIMock_Modality.text,
|
|
54
|
+
config: { maxTokens: 10 },
|
|
55
|
+
input: 'ping',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
it('| spend-guard ALAPBOL kikapcsolt → nem general, ES a generatort MEG CSAK NEM IS hivja', async () => {
|
|
60
|
+
const stub = makeStub();
|
|
61
|
+
const harness: DyNTS_AIMock_FixtureHarness_Service = new DyNTS_AIMock_FixtureHarness_Service({
|
|
62
|
+
generator: stub.generate,
|
|
63
|
+
registry: registry,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
await harness.capture(request('cheap-mini'));
|
|
68
|
+
fail('spend-guard hibat vartunk');
|
|
69
|
+
} catch (error) {
|
|
70
|
+
expect(error instanceof DyFM_Error).toBe(true);
|
|
71
|
+
if (error instanceof DyFM_Error) {
|
|
72
|
+
expect(error.message).toContain('spend-guard');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
expect(stub.calls).toBe(0);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('| D2 tier-cap: `pro` tier elutasitva, a generator nem hivodik', async () => {
|
|
80
|
+
const stub = makeStub();
|
|
81
|
+
const harness: DyNTS_AIMock_FixtureHarness_Service = new DyNTS_AIMock_FixtureHarness_Service({
|
|
82
|
+
generator: stub.generate,
|
|
83
|
+
registry: registry,
|
|
84
|
+
allowRealSpend: true,
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await expectAsync(harness.capture(request('expensive-pro'))).toBeRejected();
|
|
88
|
+
expect(stub.calls).toBe(0);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('| D2 tier-cap: `Opus` tier elutasitva (kis/nagybetu-fuggetlen)', async () => {
|
|
92
|
+
const stub = makeStub();
|
|
93
|
+
const harness: DyNTS_AIMock_FixtureHarness_Service = new DyNTS_AIMock_FixtureHarness_Service({
|
|
94
|
+
generator: stub.generate,
|
|
95
|
+
registry: registry,
|
|
96
|
+
allowRealSpend: true,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
await expectAsync(harness.capture(request('expensive-opus'))).toBeRejected();
|
|
100
|
+
expect(stub.calls).toBe(0);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('| registry-ben nem szereplo modell → elutasitva (a tier nem igazolhato)', async () => {
|
|
104
|
+
const stub = makeStub();
|
|
105
|
+
const harness: DyNTS_AIMock_FixtureHarness_Service = new DyNTS_AIMock_FixtureHarness_Service({
|
|
106
|
+
generator: stub.generate,
|
|
107
|
+
registry: registry,
|
|
108
|
+
allowRealSpend: true,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await expectAsync(harness.capture(request('nincs-ilyen'))).toBeRejected();
|
|
112
|
+
expect(stub.calls).toBe(0);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('| engedelyezett spend + olcso tier → fixture keszul, helyes mezokkel', async () => {
|
|
116
|
+
const stub = makeStub();
|
|
117
|
+
const harness: DyNTS_AIMock_FixtureHarness_Service = new DyNTS_AIMock_FixtureHarness_Service({
|
|
118
|
+
generator: stub.generate,
|
|
119
|
+
registry: registry,
|
|
120
|
+
allowRealSpend: true,
|
|
121
|
+
nowIso: (): string => '2026-07-21T00:00:00.000Z',
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const fixture: DyNTS_AIMock_Fixture = await harness.capture(request('cheap-mini'));
|
|
125
|
+
|
|
126
|
+
expect(stub.calls).toBe(1);
|
|
127
|
+
expect(fixture.output).toBe('generated-output');
|
|
128
|
+
expect(fixture.model).toBe('cheap-mini');
|
|
129
|
+
expect(fixture.modality).toBe(DyNTS_AIMock_Modality.text);
|
|
130
|
+
expect(fixture.capturedAt).toBe('2026-07-21T00:00:00.000Z');
|
|
131
|
+
expect(fixture.sourceModel).toBe('cheap-mini');
|
|
132
|
+
expect(fixture.inputHash.length).toBeGreaterThan(0);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { DyFM_Error } from '@futdevpro/fsm-dynamo';
|
|
2
|
+
import { DyFM_AI_ModelInfo, DyFM_AI_ModelRegistry_Util } from '@futdevpro/fsm-dynamo/ai';
|
|
3
|
+
|
|
4
|
+
import { DyNTS_AIMock_Request } from '../_models/interfaces/aim-request.interface';
|
|
5
|
+
import { DyNTS_AIMock_Fixture } from '../_models/interfaces/aim-fixture.interface';
|
|
6
|
+
import { DyNTS_AIMock_FixtureMatch_Util } from '../_collections/aim-fixture-match.util';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A D2 kolseg-cap altal TILTOTT modell-tier-ek (kisbetusen hasonlitva).
|
|
10
|
+
*
|
|
11
|
+
* Forras — a FR (`USER-INPUT.md`, 2026-06-22): „nem megyunk el a legmagasabb szintu modellekig, illetve nem
|
|
12
|
+
* megyunk el peldaul OpenAI Pro modellekig, de az alap, default es mini mikro modelleket szeretnem".
|
|
13
|
+
* Ezert tiltott: `pro` (gpt-5.5-pro / o3-pro / gemini-pro), `opus` (claude-opus), `flagship` (a legmagasabb
|
|
14
|
+
* szintu alap-modell). Engedett: mini / nano / legacy / flash / flash-lite / sonnet / haiku.
|
|
15
|
+
*/
|
|
16
|
+
const D2_BLOCKED_TIERS: string[] = [ 'pro', 'opus', 'flagship' ];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* **Fixture-generalo harness** (MP-3 SP-3.2) — VALODI provider-valaszbol keszit beegetheto fixture-t.
|
|
20
|
+
*
|
|
21
|
+
* **Ket egymastol fuggetlen biztonsagi zar, mert ez az egyetlen pont, ahol valodi PENZ folyhat el:**
|
|
22
|
+
* 1. **Spend-guard** — az `allowRealSpend` alapertelmezese `false`. Amig nincs EXPLICIT bekapcsolva, a harness
|
|
23
|
+
* **el sem hivja** az injektalt generatort. Igy meg egy veletlenul bekototott valodi generator sem tud
|
|
24
|
+
* hivast inditani. (G1 kapu: a bekapcsolas user-jovahagyashoz kotott.)
|
|
25
|
+
* 2. **D2 tier-cap** — a Pro / Opus / flagship tier-u modelleket elutasitja MEG a generator hivasa elott.
|
|
26
|
+
*
|
|
27
|
+
* A generator INJEKTALT (`(request) => Promise<unknown>`), ezert a harness maga soha nem fuggo halozattol —
|
|
28
|
+
* a tesztek stub-generatorral futnak, valodi hivas nelkul.
|
|
29
|
+
*/
|
|
30
|
+
export class DyNTS_AIMock_FixtureHarness_Service {
|
|
31
|
+
|
|
32
|
+
/** A valodi (vagy stub) generalo fuggveny — a harness NEM tud halozatot hivni sajat maga. */
|
|
33
|
+
private readonly generator: (request: DyNTS_AIMock_Request) => Promise<unknown>;
|
|
34
|
+
|
|
35
|
+
/** Modell-registry a tier-cap ellenorzeshez. */
|
|
36
|
+
private readonly registry: DyFM_AI_ModelInfo[];
|
|
37
|
+
|
|
38
|
+
/** Spend-guard: amig `false`, a generator NEM hivodik meg. Default: `false`. */
|
|
39
|
+
private readonly allowRealSpend: boolean;
|
|
40
|
+
|
|
41
|
+
/** Tiltott tier-ek (default: a D2 keszlet). */
|
|
42
|
+
private readonly blockedTiers: string[];
|
|
43
|
+
|
|
44
|
+
/** ISO-timestamp forras (injektalhato a determinisztikus tesztekhez). */
|
|
45
|
+
private readonly nowIso: () => string;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @param set - generator + registry + a ket biztonsagi zar beallitasa.
|
|
49
|
+
*/
|
|
50
|
+
constructor(
|
|
51
|
+
set: {
|
|
52
|
+
generator: (request: DyNTS_AIMock_Request) => Promise<unknown>,
|
|
53
|
+
registry?: DyFM_AI_ModelInfo[],
|
|
54
|
+
/** CSAK explicit `true` eseten hivodik meg a generator (G1). Default: `false`. */
|
|
55
|
+
allowRealSpend?: boolean,
|
|
56
|
+
blockedTiers?: string[],
|
|
57
|
+
nowIso?: () => string,
|
|
58
|
+
}
|
|
59
|
+
) {
|
|
60
|
+
this.generator = set.generator;
|
|
61
|
+
this.registry = set.registry ?? [];
|
|
62
|
+
this.allowRealSpend = set.allowRealSpend === true;
|
|
63
|
+
this.blockedTiers = set.blockedTiers ?? D2_BLOCKED_TIERS;
|
|
64
|
+
this.nowIso = set.nowIso ?? ((): string => new Date().toISOString());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Egy fixture rogzitese valodi generalasbol. A ket zar sorrendje: spend-guard → tier-cap → generator.
|
|
69
|
+
* @param request - a rogzitendo hivas (provider + model + modality + config + input)
|
|
70
|
+
*/
|
|
71
|
+
async capture(request: DyNTS_AIMock_Request): Promise<DyNTS_AIMock_Fixture> {
|
|
72
|
+
this.assertSpendAllowed(request);
|
|
73
|
+
this.assertTierAllowed(request);
|
|
74
|
+
|
|
75
|
+
const output: unknown = await this.generator(request);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
provider: request.provider,
|
|
79
|
+
model: request.model,
|
|
80
|
+
modality: request.modality,
|
|
81
|
+
config: request.config,
|
|
82
|
+
input: request.input,
|
|
83
|
+
inputHash: DyNTS_AIMock_FixtureMatch_Util.buildInputHash(request.input),
|
|
84
|
+
output: output,
|
|
85
|
+
capturedAt: this.nowIso(),
|
|
86
|
+
sourceModel: request.model,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** 1. zar — a spend-guard. */
|
|
91
|
+
private assertSpendAllowed(request: DyNTS_AIMock_Request): void {
|
|
92
|
+
if (this.allowRealSpend) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
throw new DyFM_Error({
|
|
97
|
+
message: `[ai-mock] real generation is DISABLED (spend-guard). Model '${request.provider}:${request.model}'. ` +
|
|
98
|
+
'Set allowRealSpend=true only with explicit approval (G1 gate).',
|
|
99
|
+
userMessage: 'Real AI generation is disabled.',
|
|
100
|
+
errorCode: 'DyNTS-AIMOCK-SPEND',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** 2. zar — a D2 tier-cap. Ismeretlen modell (nincs registry-ben) → NEM engedjuk (honesty). */
|
|
105
|
+
private assertTierAllowed(request: DyNTS_AIMock_Request): void {
|
|
106
|
+
const modelInfo: DyFM_AI_ModelInfo = DyFM_AI_ModelRegistry_Util.findModelInfo(this.registry, request.model);
|
|
107
|
+
const tier: string = (modelInfo?.tier ?? '').toLowerCase();
|
|
108
|
+
|
|
109
|
+
if (!modelInfo) {
|
|
110
|
+
throw new DyFM_Error({
|
|
111
|
+
message: `[ai-mock] model '${request.model}' is not in the registry — tier cannot be verified, ` +
|
|
112
|
+
'refusing to generate (D2 cost-cap, honesty).',
|
|
113
|
+
userMessage: 'Unknown AI model for fixture generation.',
|
|
114
|
+
errorCode: 'DyNTS-AIMOCK-TIER',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (this.blockedTiers.includes(tier)) {
|
|
119
|
+
throw new DyFM_Error({
|
|
120
|
+
message: `[ai-mock] model '${request.model}' has blocked tier '${modelInfo.tier}' (D2 cost-cap: ` +
|
|
121
|
+
`${this.blockedTiers.join(', ')}). Use a mini/nano/flash tier model for fixtures.`,
|
|
122
|
+
userMessage: 'This AI model tier is not allowed for fixture generation.',
|
|
123
|
+
errorCode: 'DyNTS-AIMOCK-TIER',
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { DyFM_AI_ModelInfo, DyFM_AI_ModelType, DyFM_AI_Provider } from '@futdevpro/fsm-dynamo/ai';
|
|
2
|
+
|
|
3
|
+
import { DyNTS_AIMock_Modality } from '../_enums/aim-modality.enum';
|
|
4
|
+
import { DyNTS_AIMock_Request } from '../_models/interfaces/aim-request.interface';
|
|
5
|
+
import { DyNTS_AIMock_Fixture } from '../_models/interfaces/aim-fixture.interface';
|
|
6
|
+
import { DyNTS_AIMock_FixtureSerializer_Util } from '../_collections/aim-fixture-serializer.util';
|
|
7
|
+
import { DyNTS_AIMock_FixtureHarness_Service } from './aim-fixture-harness.service';
|
|
8
|
+
import { DyNTS_AIMock_FixtureStore_Service } from './aim-fixture-store.service';
|
|
9
|
+
import { DyNTS_AIMock_Service } from './aim-mock.service';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* **End-to-end pipeline-bizonyitas (MP-3 + MP-4), NULLA koltessel.**
|
|
13
|
+
*
|
|
14
|
+
* A teljes fixture-eletciklust vegigviszi egyetlen teszben:
|
|
15
|
+
* `harness.capture()` (stub-generator) → `serializer.toConstantFile()` (beegetett konstans) →
|
|
16
|
+
* visszaolvasas (a generalt tomb-literal ERVENYES JSON) → `store.register()` → `service.chatCompletion()`.
|
|
17
|
+
*
|
|
18
|
+
* Ez azt igazolja, hogy a beegetett artefaktum **hianytalanul visszaallithato mukodo fixture-re** — vagyis a
|
|
19
|
+
* G1 (fizetos generalas) jovahagyasakor a gepezet mar bizonyitottan mukodik, csak valodi generatort kap.
|
|
20
|
+
*/
|
|
21
|
+
describe('| ai-mock fixture-pipeline (end-to-end, stub-generatorral)', () => {
|
|
22
|
+
|
|
23
|
+
const registry: DyFM_AI_ModelInfo[] = [
|
|
24
|
+
{
|
|
25
|
+
id: 'cheap-mini',
|
|
26
|
+
provider: DyFM_AI_Provider.OpenAI,
|
|
27
|
+
modelType: DyFM_AI_ModelType.Chat,
|
|
28
|
+
tier: 'mini',
|
|
29
|
+
capabilities: {} as any,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const request: DyNTS_AIMock_Request = {
|
|
34
|
+
provider: 'open-ai',
|
|
35
|
+
model: 'cheap-mini',
|
|
36
|
+
modality: DyNTS_AIMock_Modality.text,
|
|
37
|
+
config: { maxTokens: 32 },
|
|
38
|
+
input: 'Mi a fovarosa Magyarorszagnak?',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** A beegetett konstans-fajlbol visszaolvassa a fixture-tombot (a tomb-literal ervenyes JSON). */
|
|
42
|
+
function parseBack(source: string): DyNTS_AIMock_Fixture[] {
|
|
43
|
+
const start: number = source.indexOf('= [') + 2;
|
|
44
|
+
const end: number = source.lastIndexOf('];') + 1;
|
|
45
|
+
|
|
46
|
+
return JSON.parse(source.slice(start, end));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
it('| capture → serialize → parse-back → store → replay: a beegetett ertek jon vissza', async () => {
|
|
50
|
+
// 1) GENERALAS — stub-generator, NULLA valodi hivas. A spend-guard explicit engedelyezve CSAK a stubhoz.
|
|
51
|
+
const harness: DyNTS_AIMock_FixtureHarness_Service = new DyNTS_AIMock_FixtureHarness_Service({
|
|
52
|
+
generator: async (): Promise<unknown> => 'Budapest.',
|
|
53
|
+
registry: registry,
|
|
54
|
+
allowRealSpend: true,
|
|
55
|
+
nowIso: (): string => '2026-07-21T00:00:00.000Z',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const captured: DyNTS_AIMock_Fixture = await harness.capture(request);
|
|
59
|
+
|
|
60
|
+
// 2) BEEGETES — determinisztikus TS-konstans fajl tartalma
|
|
61
|
+
const fileSource: string = DyNTS_AIMock_FixtureSerializer_Util.toConstantFile({
|
|
62
|
+
constName: 'DyNTS_AIMock_PipelineFixtures',
|
|
63
|
+
fixtures: [ captured ],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(fileSource).toContain('export const DyNTS_AIMock_PipelineFixtures');
|
|
67
|
+
|
|
68
|
+
// 3) VISSZAOLVASAS — a beegetett artefaktumbol ujra fixture-objektum
|
|
69
|
+
const reloaded: DyNTS_AIMock_Fixture[] = parseBack(fileSource);
|
|
70
|
+
|
|
71
|
+
expect(reloaded.length).toBe(1);
|
|
72
|
+
expect(reloaded[0].inputHash).toBe(captured.inputHash);
|
|
73
|
+
|
|
74
|
+
// 4) REPLAY — a visszaolvasott fixture-t a store-ba tolve a mock ugyanazt adja vissza
|
|
75
|
+
const store: DyNTS_AIMock_FixtureStore_Service = new DyNTS_AIMock_FixtureStore_Service(reloaded);
|
|
76
|
+
const service: DyNTS_AIMock_Service = new DyNTS_AIMock_Service(store, registry);
|
|
77
|
+
|
|
78
|
+
await expectAsync(
|
|
79
|
+
service.chatCompletion({
|
|
80
|
+
provider: 'open-ai',
|
|
81
|
+
model: 'cheap-mini',
|
|
82
|
+
config: { maxTokens: 32 },
|
|
83
|
+
input: 'Mi a fovarosa Magyarorszagnak?',
|
|
84
|
+
})
|
|
85
|
+
).toBeResolvedTo('Budapest.');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('| a beegetes/visszaolvasas kortje IDEMPOTENS (ketszer szerializalva azonos fajl)', async () => {
|
|
89
|
+
const harness: DyNTS_AIMock_FixtureHarness_Service = new DyNTS_AIMock_FixtureHarness_Service({
|
|
90
|
+
generator: async (): Promise<unknown> => 'Budapest.',
|
|
91
|
+
registry: registry,
|
|
92
|
+
allowRealSpend: true,
|
|
93
|
+
nowIso: (): string => '2026-07-21T00:00:00.000Z',
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const captured: DyNTS_AIMock_Fixture = await harness.capture(request);
|
|
97
|
+
const first: string = DyNTS_AIMock_FixtureSerializer_Util.toConstantFile({ constName: 'X', fixtures: [ captured ] });
|
|
98
|
+
const second: string = DyNTS_AIMock_FixtureSerializer_Util.toConstantFile({
|
|
99
|
+
constName: 'X',
|
|
100
|
+
fixtures: parseBack(first),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(second).toBe(first);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { DyNTS_AIMock_Modality } from '../_enums/aim-modality.enum';
|
|
2
|
+
import { DyNTS_AIMock_Request } from '../_models/interfaces/aim-request.interface';
|
|
3
|
+
import { DyNTS_AIMock_Fixture } from '../_models/interfaces/aim-fixture.interface';
|
|
4
|
+
import { DyNTS_AIMock_FixtureMatch_Util } from '../_collections/aim-fixture-match.util';
|
|
5
|
+
import { DyNTS_AIMock_FixtureStore_Service } from './aim-fixture-store.service';
|
|
6
|
+
|
|
7
|
+
describe('DyNTS_AIMock_FixtureStore_Service', () => {
|
|
8
|
+
|
|
9
|
+
const fixture: DyNTS_AIMock_Fixture = {
|
|
10
|
+
provider: 'open-ai',
|
|
11
|
+
model: 'gpt-4o-mini',
|
|
12
|
+
modality: DyNTS_AIMock_Modality.text,
|
|
13
|
+
config: { temperature: 0 },
|
|
14
|
+
input: 'ping',
|
|
15
|
+
inputHash: DyNTS_AIMock_FixtureMatch_Util.buildInputHash('ping'),
|
|
16
|
+
output: 'pong',
|
|
17
|
+
capturedAt: '2026-07-21T00:00:00.000Z',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const hitRequest: DyNTS_AIMock_Request = {
|
|
21
|
+
provider: 'open-ai',
|
|
22
|
+
model: 'gpt-4o-mini',
|
|
23
|
+
modality: DyNTS_AIMock_Modality.text,
|
|
24
|
+
config: { temperature: 0 },
|
|
25
|
+
input: 'ping',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
it('register + resolve hit → a fixture', () => {
|
|
29
|
+
const store: DyNTS_AIMock_FixtureStore_Service = new DyNTS_AIMock_FixtureStore_Service([fixture]);
|
|
30
|
+
|
|
31
|
+
expect(store.resolve(hitRequest)).toBe(fixture);
|
|
32
|
+
expect(store.has(hitRequest)).toBe(true);
|
|
33
|
+
expect(store.size).toBe(1);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('resolve miss → undefined + has false', () => {
|
|
37
|
+
const store: DyNTS_AIMock_FixtureStore_Service = new DyNTS_AIMock_FixtureStore_Service([fixture]);
|
|
38
|
+
const miss: DyNTS_AIMock_Request = { ...hitRequest, input: 'unknown' };
|
|
39
|
+
|
|
40
|
+
expect(store.resolve(miss)).toBeUndefined();
|
|
41
|
+
expect(store.has(miss)).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('resolve config-sorrend-független hit', () => {
|
|
45
|
+
const store: DyNTS_AIMock_FixtureStore_Service = new DyNTS_AIMock_FixtureStore_Service([fixture]);
|
|
46
|
+
const reordered: DyNTS_AIMock_Request = { ...hitRequest, config: { temperature: 0 } };
|
|
47
|
+
|
|
48
|
+
expect(store.resolve(reordered)).toBe(fixture);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { DyNTS_AIMock_Request } from '../_models/interfaces/aim-request.interface';
|
|
2
|
+
import { DyNTS_AIMock_Fixture } from '../_models/interfaces/aim-fixture.interface';
|
|
3
|
+
import { DyNTS_AIMock_FixtureMatch_Util } from '../_collections/aim-fixture-match.util';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A beégetett fixture-ök tára — match-kulcs → fixture Map (lazy-cache; a Map MAGA a cache). A fixture-öket
|
|
7
|
+
* konstans-blob-fájlokból (D6, git-tracked) importáljuk és `register`-rel adjuk be; a runtime-feloldás a
|
|
8
|
+
* `DyNTS_AIMock_FixtureMatch_Util.buildMatchKey`-en megy (config-sorrend- + input-whitespace-független).
|
|
9
|
+
* A reject-on-unknown (D3) NEM itt dől el — a `resolve` `undefined`-et ad, a hívó (`DyNTS_AIMock_Service`)
|
|
10
|
+
* dob strukturált „no-fixture" hibát. Ez a réteg tiszta, hálózat-mentes — NEM generál (SP-3.2 = G1 gate).
|
|
11
|
+
*/
|
|
12
|
+
export class DyNTS_AIMock_FixtureStore_Service {
|
|
13
|
+
|
|
14
|
+
/** match-kulcs → fixture. */
|
|
15
|
+
private readonly fixturesByKey: Map<string, DyNTS_AIMock_Fixture> = new Map();
|
|
16
|
+
|
|
17
|
+
/** @param fixtures opcionális kezdő-készlet (konstans-blob-okból). */
|
|
18
|
+
constructor(fixtures?: DyNTS_AIMock_Fixture[]) {
|
|
19
|
+
if (fixtures?.length) {
|
|
20
|
+
this.register(fixtures);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Fixture-ök beindexelése (match-kulcs szerint). Azonos kulcsú fixture felülírja a korábbit (last-wins).
|
|
26
|
+
* @param fixtures - a beégetett fixture-rekordok
|
|
27
|
+
*/
|
|
28
|
+
register(fixtures: DyNTS_AIMock_Fixture[]): void {
|
|
29
|
+
for (const fixture of fixtures) {
|
|
30
|
+
this.fixturesByKey.set(this.keyOf(fixture), fixture);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Input-match feloldás: hit → fixture; miss → `undefined` (a reject-on-unknown a hívó dolga).
|
|
36
|
+
* @param request - a mock-hívás bemenete
|
|
37
|
+
*/
|
|
38
|
+
resolve(request: DyNTS_AIMock_Request): DyNTS_AIMock_Fixture | undefined {
|
|
39
|
+
return this.fixturesByKey.get(DyNTS_AIMock_FixtureMatch_Util.buildMatchKey(request));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Van-e fixture az adott request-re.
|
|
44
|
+
* @param request - a mock-hívás bemenete
|
|
45
|
+
*/
|
|
46
|
+
has(request: DyNTS_AIMock_Request): boolean {
|
|
47
|
+
return this.fixturesByKey.has(DyNTS_AIMock_FixtureMatch_Util.buildMatchKey(request));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** A beindexelt fixture-ök száma. */
|
|
51
|
+
get size(): number {
|
|
52
|
+
return this.fixturesByKey.size;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A fixture match-kulcsa a saját nyers mezőiből (a `resolve`-val szimmetrikusan képezve). */
|
|
56
|
+
private keyOf(fixture: DyNTS_AIMock_Fixture): string {
|
|
57
|
+
return DyNTS_AIMock_FixtureMatch_Util.buildMatchKey({
|
|
58
|
+
provider: fixture.provider,
|
|
59
|
+
model: fixture.model,
|
|
60
|
+
modality: fixture.modality,
|
|
61
|
+
config: fixture.config,
|
|
62
|
+
input: fixture.input,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { DyFM_Error } from '@futdevpro/fsm-dynamo';
|
|
2
|
+
import { DyFM_AI_ModelInfo, DyFM_AI_ModelType, DyFM_AI_Provider } from '@futdevpro/fsm-dynamo/ai';
|
|
3
|
+
|
|
4
|
+
import { DyNTS_AIMock_Modality } from '../_enums/aim-modality.enum';
|
|
5
|
+
import { DyNTS_AIMock_Fixture } from '../_models/interfaces/aim-fixture.interface';
|
|
6
|
+
import { DyNTS_AIMock_FixtureMatch_Util } from '../_collections/aim-fixture-match.util';
|
|
7
|
+
import { DyNTS_AIMock_FixtureStore_Service } from './aim-fixture-store.service';
|
|
8
|
+
import { DyNTS_AIMock_Service } from './aim-mock.service';
|
|
9
|
+
|
|
10
|
+
describe('DyNTS_AIMock_Service', () => {
|
|
11
|
+
|
|
12
|
+
const okFixture: DyNTS_AIMock_Fixture = {
|
|
13
|
+
provider: 'open-ai',
|
|
14
|
+
model: 'gpt-4o-mini',
|
|
15
|
+
modality: DyNTS_AIMock_Modality.text,
|
|
16
|
+
config: { temperature: 0 },
|
|
17
|
+
input: 'ping',
|
|
18
|
+
inputHash: DyNTS_AIMock_FixtureMatch_Util.buildInputHash('ping'),
|
|
19
|
+
output: 'pong',
|
|
20
|
+
capturedAt: '2026-07-21T00:00:00.000Z',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const errFixture: DyNTS_AIMock_Fixture = {
|
|
24
|
+
provider: 'open-ai',
|
|
25
|
+
model: 'gpt-4o-mini',
|
|
26
|
+
modality: DyNTS_AIMock_Modality.text,
|
|
27
|
+
config: { temperature: 0.5 },
|
|
28
|
+
input: 'bad',
|
|
29
|
+
inputHash: DyNTS_AIMock_FixtureMatch_Util.buildInputHash('bad'),
|
|
30
|
+
error: {
|
|
31
|
+
httpStatus: 400,
|
|
32
|
+
providerErrorBody: { error: { type: 'invalid_request_error', param: 'temperature', code: 'unsupported_parameter' } },
|
|
33
|
+
reason: 'unsupported_parameter:temperature',
|
|
34
|
+
},
|
|
35
|
+
capturedAt: '2026-07-21T00:00:00.000Z',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function makeService(fixtures: DyNTS_AIMock_Fixture[]): DyNTS_AIMock_Service {
|
|
39
|
+
return new DyNTS_AIMock_Service(new DyNTS_AIMock_FixtureStore_Service(fixtures));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
it('replay hit → a beégetett output', async () => {
|
|
43
|
+
const service: DyNTS_AIMock_Service = makeService([okFixture]);
|
|
44
|
+
|
|
45
|
+
await expectAsync(
|
|
46
|
+
service.chatCompletion({ provider: 'open-ai', model: 'gpt-4o-mini', config: { temperature: 0 }, input: 'ping' })
|
|
47
|
+
).toBeResolvedTo('pong');
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('miss → reject-on-unknown (DyNTS-AIMOCK-NOFIX), NEM silent', async () => {
|
|
51
|
+
const service: DyNTS_AIMock_Service = makeService([okFixture]);
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
await service.chatCompletion({ provider: 'open-ai', model: 'gpt-4o-mini', input: 'unknown' });
|
|
55
|
+
fail('reject-on-unknown vártunk');
|
|
56
|
+
} catch (error) {
|
|
57
|
+
expect(error instanceof DyFM_Error).toBe(true);
|
|
58
|
+
if (error instanceof DyFM_Error) {
|
|
59
|
+
expect(error.message).toContain('no fixture');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('FR-048 config-check: NEM támogatott param → provider-faithful 400, MÉG fixture-lookup előtt', async () => {
|
|
65
|
+
const registry: DyFM_AI_ModelInfo[] = [
|
|
66
|
+
{
|
|
67
|
+
id: 'gpt-4o-mini',
|
|
68
|
+
provider: DyFM_AI_Provider.OpenAI,
|
|
69
|
+
modelType: DyFM_AI_ModelType.Chat,
|
|
70
|
+
capabilities: {} as any,
|
|
71
|
+
settingsSchema: { unsupported: ['temperature'] },
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
// A store URES → ha a config-check NEM futna, 'no fixture' jonne; igy bizonyitjuk a sorrendet.
|
|
75
|
+
const service: DyNTS_AIMock_Service = new DyNTS_AIMock_Service(
|
|
76
|
+
new DyNTS_AIMock_FixtureStore_Service([]),
|
|
77
|
+
registry
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
await service.chatCompletion({ provider: 'open-ai', model: 'gpt-4o-mini', config: { temperature: 0.5 }, input: 'x' });
|
|
82
|
+
fail('provider-faithful 400-at vártunk');
|
|
83
|
+
} catch (error) {
|
|
84
|
+
expect(error instanceof DyFM_Error).toBe(true);
|
|
85
|
+
if (error instanceof DyFM_Error) {
|
|
86
|
+
expect(error.message).toContain('unsupported_parameter:temperature');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('FR-048 config-check: registry nélkül permisszív (nem találgat) → a fixture-replay dönt', async () => {
|
|
92
|
+
const service: DyNTS_AIMock_Service = makeService([okFixture]);
|
|
93
|
+
|
|
94
|
+
await expectAsync(
|
|
95
|
+
service.chatCompletion({ provider: 'open-ai', model: 'gpt-4o-mini', config: { temperature: 0 }, input: 'ping' })
|
|
96
|
+
).toBeResolvedTo('pong');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('beégetett error → provider-faithful hiba (DyNTS-AIMOCK-PERR)', async () => {
|
|
100
|
+
const service: DyNTS_AIMock_Service = makeService([errFixture]);
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
await service.chatCompletion({ provider: 'open-ai', model: 'gpt-4o-mini', config: { temperature: 0.5 }, input: 'bad' });
|
|
104
|
+
fail('provider-faithful hibát vártunk');
|
|
105
|
+
} catch (error) {
|
|
106
|
+
expect(error instanceof DyFM_Error).toBe(true);
|
|
107
|
+
if (error instanceof DyFM_Error) {
|
|
108
|
+
expect(error.message).toContain('provider-faithful error');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|