mdi-llmkit 1.0.5 → 1.0.6
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/README.md
CHANGED
|
@@ -160,31 +160,11 @@ const result = await gptSubmit(
|
|
|
160
160
|
console.log(result);
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
## Notes
|
|
164
|
-
|
|
165
|
-
- Current TypeScript parity slices include `gptSubmit`, `GptConversation`, and `JSONSchemaFormat`.
|
|
166
|
-
- You can import GPT API symbols via subpath imports, e.g. `import { GptConversation } from "mdi-llmkit/gptApi"`.
|
|
167
|
-
- Comparison symbols are available via `mdi-llmkit/comparison`.
|
|
168
|
-
- Integer schemas can be expressed with `JSON_INTEGER`; numeric (float-capable) schemas can use `JSON_NUMBER`.
|
|
169
|
-
|
|
170
|
-
## Migration from Python
|
|
171
|
-
|
|
172
|
-
- Function naming: Python `gpt_submit(...)` maps to TypeScript `gptSubmit(...)`.
|
|
173
|
-
- Argument style: Python keyword args map to a TypeScript options object.
|
|
174
|
-
- Conversation submit methods: Python `submit_user_message(...)` maps to `submitUserMessage(...)`.
|
|
175
|
-
- JSON schema DSL: Python tuple metadata uses TypeScript array metadata.
|
|
176
|
-
- Python: `("Age", (0, 120), int)`
|
|
177
|
-
- TypeScript: `["Age", [0, 120], JSON_INTEGER]`
|
|
178
|
-
- JSON schema type markers in TypeScript:
|
|
179
|
-
- `JSON_INTEGER` for integer-only values.
|
|
180
|
-
- `JSON_NUMBER` for float-capable numeric values.
|
|
181
163
|
|
|
182
164
|
## CI and Release
|
|
183
165
|
|
|
184
|
-
- CI workflow: `.github/workflows/typescript-
|
|
185
|
-
- Runs on
|
|
166
|
+
- Unified CI + release workflow: `.github/workflows/typescript-release.yml`
|
|
167
|
+
- Runs CI on pull requests and on pushes to `main` when TypeScript package files change.
|
|
186
168
|
- Executes `npm ci`, `npm test`, and `npm run build` in `packages/typescript-mdi-llmkit`.
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
- Requires repository secret `NPM_TOKEN` with publish permission to npm.
|
|
190
|
-
- Executes tests/build before `npm publish --access public --provenance`.
|
|
169
|
+
- On push to `main`, publishes to npm only if `package.json` version changed and that version is not already published.
|
|
170
|
+
- Uses repository secret `NPM_TOKEN` for npm authentication.
|
|
@@ -35,16 +35,16 @@ const assertProcessedCountersAreSequential = (events) => {
|
|
|
35
35
|
expect(finishes[finishes.length - 1].totalLeftToProcess).toBe(0);
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
-
describe
|
|
38
|
+
describe('compareItemLists (live API)', () => {
|
|
39
39
|
// IMPORTANT: These tests intentionally use live OpenAI calls and DO NOT mock GptConversation.
|
|
40
40
|
// We are validating the real prompt+schema behavior end-to-end (including model decisions),
|
|
41
41
|
// not just local control-flow in isolation.
|
|
42
|
-
describe
|
|
42
|
+
describe('input validation', () => {
|
|
43
43
|
it('throws for duplicate item names (case-insensitive) within a list', async () => {
|
|
44
44
|
await expect(compareItemLists(createClient(), ['Widget', 'widget'], ['Other'])).rejects.toThrow('Duplicate item names found in before list');
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
|
-
describe
|
|
47
|
+
describe('string behavior', () => {
|
|
48
48
|
it('classifies case-insensitive exact string matches as unchanged', async () => {
|
|
49
49
|
const { events, callback } = collectEvents();
|
|
50
50
|
const result = await compareItemLists(createClient(), ['String Item A', 'String Item B'], ['string item a', 'STRING ITEM B'], 'Case-only differences are unchanged.', callback);
|
|
@@ -56,7 +56,7 @@ describe.concurrent('compareItemLists (live API)', () => {
|
|
|
56
56
|
expect(events).toHaveLength(0);
|
|
57
57
|
}, 180000);
|
|
58
58
|
});
|
|
59
|
-
describe
|
|
59
|
+
describe('name/description behavior', () => {
|
|
60
60
|
it('treats same names as unchanged even when descriptions differ', async () => {
|
|
61
61
|
const result = await compareItemLists(createClient(), [
|
|
62
62
|
{
|
|
@@ -94,7 +94,7 @@ describe.concurrent('compareItemLists (live API)', () => {
|
|
|
94
94
|
expect(result.renamed['Plan Bronze Legacy']).toBe('Plan Bronze Modern');
|
|
95
95
|
}, 180000);
|
|
96
96
|
});
|
|
97
|
-
describe
|
|
97
|
+
describe('rename behavior', () => {
|
|
98
98
|
it('detects a single guided rename', async () => {
|
|
99
99
|
const result = await compareItemLists(createClient(), ['ACME Legacy Plan'], ['ACME Modern Plan'], 'There is exactly one rename in this migration. ' +
|
|
100
100
|
'ACME Legacy Plan was renamed to ACME Modern Plan. ' +
|
|
@@ -120,7 +120,7 @@ describe.concurrent('compareItemLists (live API)', () => {
|
|
|
120
120
|
expect(result.unchanged).toEqual([]);
|
|
121
121
|
}, 180000);
|
|
122
122
|
});
|
|
123
|
-
describe
|
|
123
|
+
describe('added/deleted behavior', () => {
|
|
124
124
|
it('classifies explicit deletion', async () => {
|
|
125
125
|
const result = await compareItemLists(createClient(), ['Delete Me Item'], [], 'Delete Me Item was intentionally removed and has no replacement.');
|
|
126
126
|
expect(result.removed).toEqual(['Delete Me Item']);
|
|
@@ -136,7 +136,7 @@ describe.concurrent('compareItemLists (live API)', () => {
|
|
|
136
136
|
expect(result.unchanged).toEqual([]);
|
|
137
137
|
}, 180000);
|
|
138
138
|
});
|
|
139
|
-
describe
|
|
139
|
+
describe('mixed outcomes', () => {
|
|
140
140
|
it('handles unchanged + renamed + removed + added together', async () => {
|
|
141
141
|
const result = await compareItemLists(createClient(), ['Shared Constant Item', 'Legacy Rename Target', 'Delete Candidate'], ['shared constant item', 'Modern Rename Target', 'Add Candidate'], 'Legacy Rename Target was renamed to Modern Rename Target. ' +
|
|
142
142
|
'Delete Candidate was removed. ' +
|
|
@@ -148,7 +148,7 @@ describe.concurrent('compareItemLists (live API)', () => {
|
|
|
148
148
|
expect(result.added).toEqual(['Add Candidate']);
|
|
149
149
|
}, 180000);
|
|
150
150
|
});
|
|
151
|
-
describe
|
|
151
|
+
describe('callback reporting behavior', () => {
|
|
152
152
|
it('emits balanced start/finish events with correct source-list flags', async () => {
|
|
153
153
|
const { events, callback } = collectEvents();
|
|
154
154
|
await compareItemLists(createClient(), ['Before Removed A', 'Before Removed B'], ['After Added A'], 'Before Removed A and Before Removed B were removed. ' +
|
|
@@ -192,7 +192,7 @@ describe.concurrent('compareItemLists (live API)', () => {
|
|
|
192
192
|
expect(finishEventsWithErrors.some((event) => (event.error || '').includes('LLM processing failed'))).toBe(true);
|
|
193
193
|
}, 180000);
|
|
194
194
|
});
|
|
195
|
-
describe
|
|
195
|
+
describe('bulk list scenarios', () => {
|
|
196
196
|
it('handles a larger mixed migration with multiple renames/additions/deletions', async () => {
|
|
197
197
|
const beforeItems = [
|
|
198
198
|
'Shared Stable A',
|
|
@@ -269,7 +269,7 @@ describe.concurrent('compareItemLists (live API)', () => {
|
|
|
269
269
|
assertProcessedCountersAreSequential(events);
|
|
270
270
|
}, 240000);
|
|
271
271
|
});
|
|
272
|
-
describe
|
|
272
|
+
describe('inference without explicit mapping instructions', () => {
|
|
273
273
|
it('infers removed string items when after list omits them', async () => {
|
|
274
274
|
const result = await compareItemLists(createClient(), [
|
|
275
275
|
'Invoice Number',
|
|
@@ -8,7 +8,7 @@ if (!OPENAI_API_KEY) {
|
|
|
8
8
|
const createClient = () => new OpenAI({
|
|
9
9
|
apiKey: OPENAI_API_KEY,
|
|
10
10
|
});
|
|
11
|
-
describe
|
|
11
|
+
describe('jsonSurgery (live API)', () => {
|
|
12
12
|
describe('atomic operations', () => {
|
|
13
13
|
it('applies a simple scalar update without mutating original input', async () => {
|
|
14
14
|
const original = {
|