@hardlydifficult/ai-msg 1.0.0 → 1.0.2
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 +46 -40
- package/dist/extractJson.d.ts +1 -1
- package/dist/extractJson.d.ts.map +1 -1
- package/dist/extractJson.js +26 -17
- package/dist/extractJson.js.map +1 -1
- package/dist/extractTyped.d.ts +14 -2
- package/dist/extractTyped.d.ts.map +1 -1
- package/dist/extractTyped.js +9 -6
- package/dist/extractTyped.js.map +1 -1
- package/dist/findBalanced.d.ts +1 -0
- package/dist/findBalanced.d.ts.map +1 -1
- package/dist/findBalanced.js +16 -0
- package/dist/findBalanced.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/multimodal.d.ts +25 -0
- package/dist/multimodal.d.ts.map +1 -0
- package/dist/multimodal.js +28 -0
- package/dist/multimodal.js.map +1 -0
- package/package.json +1 -9
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# @hardlydifficult/ai-msg
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
LLM responses often wrap structured data in markdown code blocks, preamble text, or trailing commentary. This package reliably extracts JSON and code blocks from messy AI output.
|
|
3
|
+
Extract structured data from AI model responses: JSON, typed schemas, code blocks, and multimodal content.
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
@@ -10,43 +8,53 @@ LLM responses often wrap structured data in markdown code blocks, preamble text,
|
|
|
10
8
|
npm install @hardlydifficult/ai-msg
|
|
11
9
|
```
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install @hardlydifficult/ai-msg zod
|
|
17
|
-
```
|
|
11
|
+
## API
|
|
18
12
|
|
|
19
|
-
|
|
13
|
+
### `extractJson(text: string, sentinel?: string): unknown[]`
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
Extract JSON objects/arrays from AI response text. Uses a three-pass strategy:
|
|
22
16
|
|
|
23
|
-
|
|
17
|
+
1. Parse the entire text as JSON
|
|
18
|
+
2. Extract from fenced code blocks (json-tagged first, then any)
|
|
19
|
+
3. Find balanced `{}`/`[]` in prose
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
2. Search markdown code blocks (json-tagged first, then any)
|
|
27
|
-
3. Find balanced `{}` or `[]` substrings in prose
|
|
21
|
+
Pass a `sentinel` string to return `[]` when the response contains it (useful for "no results" markers).
|
|
28
22
|
|
|
29
|
-
|
|
23
|
+
````typescript
|
|
30
24
|
import { extractJson } from "@hardlydifficult/ai-msg";
|
|
31
25
|
|
|
32
|
-
extractJson('{"key": "value"}');
|
|
33
|
-
// { key: "value" }
|
|
34
|
-
|
|
35
26
|
extractJson('Here is the result:\n```json\n{"key": "value"}\n```\nDone.');
|
|
36
|
-
// { key: "value" }
|
|
27
|
+
// [{ key: "value" }]
|
|
37
28
|
|
|
38
|
-
extractJson('
|
|
39
|
-
// {
|
|
29
|
+
extractJson('First {"a": 1} then {"b": 2} done.');
|
|
30
|
+
// [{ a: 1 }, { b: 2 }]
|
|
40
31
|
|
|
41
|
-
extractJson("
|
|
42
|
-
//
|
|
43
|
-
|
|
32
|
+
extractJson("NO_FINDINGS: scan completed.", "NO_FINDINGS");
|
|
33
|
+
// []
|
|
34
|
+
````
|
|
44
35
|
|
|
45
|
-
### `
|
|
36
|
+
### `extractTyped<T>(text: string, schema: SchemaLike<T>, sentinel?: string): T[]`
|
|
46
37
|
|
|
47
|
-
|
|
38
|
+
Extract and validate JSON against a schema. Works with Zod 3, Zod 4, or any object with a `safeParse` method. Only returns entries that pass validation.
|
|
48
39
|
|
|
49
40
|
```typescript
|
|
41
|
+
import { extractTyped } from "@hardlydifficult/ai-msg";
|
|
42
|
+
import { z } from "zod";
|
|
43
|
+
|
|
44
|
+
const Person = z.object({ name: z.string(), age: z.number() });
|
|
45
|
+
|
|
46
|
+
extractTyped('{"name": "Alice", "age": 30}', Person);
|
|
47
|
+
// [{ name: "Alice", age: 30 }]
|
|
48
|
+
|
|
49
|
+
extractTyped('{"name": "Alice", "age": "thirty"}', Person);
|
|
50
|
+
// [] — fails validation
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### `extractCodeBlock(text: string, lang?: string): string[]`
|
|
54
|
+
|
|
55
|
+
Extract fenced code block contents. Optionally filter by language tag.
|
|
56
|
+
|
|
57
|
+
````typescript
|
|
50
58
|
import { extractCodeBlock } from "@hardlydifficult/ai-msg";
|
|
51
59
|
|
|
52
60
|
extractCodeBlock("```ts\nconst x = 1;\n```");
|
|
@@ -54,24 +62,22 @@ extractCodeBlock("```ts\nconst x = 1;\n```");
|
|
|
54
62
|
|
|
55
63
|
extractCodeBlock("```json\n{}\n```\n```ts\nconst x = 1;\n```", "json");
|
|
56
64
|
// ["{}"]
|
|
65
|
+
````
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
// []
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### `extractTyped<T>(text, schema): T | null`
|
|
67
|
+
### `extractTextContent(content: string | { type: string; text?: string }[]): string`
|
|
63
68
|
|
|
64
|
-
|
|
69
|
+
Extract plain text from a message content field. Handles both plain strings and multimodal content arrays (AI SDK format).
|
|
65
70
|
|
|
66
71
|
```typescript
|
|
67
|
-
import {
|
|
68
|
-
import { z } from "zod";
|
|
72
|
+
import { extractTextContent } from "@hardlydifficult/ai-msg";
|
|
69
73
|
|
|
70
|
-
|
|
74
|
+
extractTextContent("hello"); // "hello"
|
|
75
|
+
extractTextContent([
|
|
76
|
+
{ type: "text", text: "hello" },
|
|
77
|
+
{ type: "image_url", url: "..." },
|
|
78
|
+
]); // "hello"
|
|
79
|
+
```
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
// { name: "Alice", age: 30 }
|
|
81
|
+
### `toPlainTextMessages(messages: MultimodalMessage[]): { role, content }[]`
|
|
74
82
|
|
|
75
|
-
|
|
76
|
-
// null
|
|
77
|
-
```
|
|
83
|
+
Convert multimodal messages to plain text messages by flattening content arrays.
|
package/dist/extractJson.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function extractJson(text: string): unknown;
|
|
1
|
+
export declare function extractJson(text: string, sentinel?: string): unknown[];
|
|
2
2
|
//# sourceMappingURL=extractJson.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractJson.d.ts","sourceRoot":"","sources":["../src/extractJson.ts"],"names":[],"mappings":"AAWA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"extractJson.d.ts","sourceRoot":"","sources":["../src/extractJson.ts"],"names":[],"mappings":"AAWA,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAgDtE"}
|
package/dist/extractJson.js
CHANGED
|
@@ -11,40 +11,49 @@ function tryParse(text) {
|
|
|
11
11
|
return undefined;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
function extractJson(text) {
|
|
14
|
+
function extractJson(text, sentinel) {
|
|
15
|
+
// Sentinel check — if the text contains the sentinel, treat as "no findings"
|
|
16
|
+
if (sentinel !== undefined && text.includes(sentinel)) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
15
19
|
// Pass 1: try the whole text
|
|
16
20
|
const direct = tryParse(text.trim());
|
|
17
21
|
if (direct !== undefined) {
|
|
18
|
-
return direct;
|
|
22
|
+
return [direct];
|
|
19
23
|
}
|
|
20
24
|
// Pass 2: code blocks — json-tagged first, then any
|
|
25
|
+
const fromBlocks = [];
|
|
21
26
|
for (const block of (0, extractCodeBlock_js_1.extractCodeBlock)(text, "json")) {
|
|
22
27
|
const parsed = tryParse(block.trim());
|
|
23
28
|
if (parsed !== undefined) {
|
|
24
|
-
|
|
29
|
+
fromBlocks.push(parsed);
|
|
25
30
|
}
|
|
26
31
|
}
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
if (fromBlocks.length === 0) {
|
|
33
|
+
for (const block of (0, extractCodeBlock_js_1.extractCodeBlock)(text)) {
|
|
34
|
+
const parsed = tryParse(block.trim());
|
|
35
|
+
if (parsed !== undefined) {
|
|
36
|
+
fromBlocks.push(parsed);
|
|
37
|
+
}
|
|
31
38
|
}
|
|
32
39
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
if (fromBlocks.length > 0) {
|
|
41
|
+
return fromBlocks;
|
|
42
|
+
}
|
|
43
|
+
// Pass 3: all balanced braces / brackets in prose
|
|
44
|
+
const results = [];
|
|
45
|
+
for (const match of (0, findBalanced_js_1.findAllBalanced)(text, "{", "}")) {
|
|
46
|
+
const parsed = tryParse(match);
|
|
37
47
|
if (parsed !== undefined) {
|
|
38
|
-
|
|
48
|
+
results.push(parsed);
|
|
39
49
|
}
|
|
40
50
|
}
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const parsed = tryParse(arr);
|
|
51
|
+
for (const match of (0, findBalanced_js_1.findAllBalanced)(text, "[", "]")) {
|
|
52
|
+
const parsed = tryParse(match);
|
|
44
53
|
if (parsed !== undefined) {
|
|
45
|
-
|
|
54
|
+
results.push(parsed);
|
|
46
55
|
}
|
|
47
56
|
}
|
|
48
|
-
return
|
|
57
|
+
return results;
|
|
49
58
|
}
|
|
50
59
|
//# sourceMappingURL=extractJson.js.map
|
package/dist/extractJson.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractJson.js","sourceRoot":"","sources":["../src/extractJson.ts"],"names":[],"mappings":";;AAWA,
|
|
1
|
+
{"version":3,"file":"extractJson.js","sourceRoot":"","sources":["../src/extractJson.ts"],"names":[],"mappings":";;AAWA,kCAgDC;AA3DD,+DAAyD;AACzD,uDAAoD;AAEpD,SAAS,QAAQ,CAAC,IAAY;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAgB,WAAW,CAAC,IAAY,EAAE,QAAiB;IACzD,6EAA6E;IAC7E,IAAI,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,6BAA6B;IAC7B,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACrC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IAED,oDAAoD;IACpD,MAAM,UAAU,GAAc,EAAE,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,IAAA,sCAAgB,EAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;QACnD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,IAAA,sCAAgB,EAAC,IAAI,CAAC,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YACtC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,kDAAkD;IAClD,MAAM,OAAO,GAAc,EAAE,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,IAAA,iCAAe,EAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,IAAA,iCAAe,EAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/extractTyped.d.ts
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Any schema with a safeParse method (e.g. Zod 3, Zod 4, or custom).
|
|
3
|
+
* Using a structural type avoids coupling to a specific Zod version.
|
|
4
|
+
*/
|
|
5
|
+
export interface SchemaLike<T> {
|
|
6
|
+
safeParse(data: unknown): {
|
|
7
|
+
success: true;
|
|
8
|
+
data: T;
|
|
9
|
+
} | {
|
|
10
|
+
success: false;
|
|
11
|
+
error?: unknown;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export declare function extractTyped<T>(text: string, schema: SchemaLike<T>, sentinel?: string): T[];
|
|
3
15
|
//# sourceMappingURL=extractTyped.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractTyped.d.ts","sourceRoot":"","sources":["../src/extractTyped.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extractTyped.d.ts","sourceRoot":"","sources":["../src/extractTyped.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,SAAS,CACP,IAAI,EAAE,OAAO,GACZ;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,CAAC,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACrE;AAED,wBAAgB,YAAY,CAAC,CAAC,EAC5B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,EACrB,QAAQ,CAAC,EAAE,MAAM,GAChB,CAAC,EAAE,CAUL"}
|
package/dist/extractTyped.js
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractTyped = extractTyped;
|
|
4
4
|
const extractJson_js_1 = require("./extractJson.js");
|
|
5
|
-
function extractTyped(text, schema) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
function extractTyped(text, schema, sentinel) {
|
|
6
|
+
const results = (0, extractJson_js_1.extractJson)(text, sentinel);
|
|
7
|
+
const validated = [];
|
|
8
|
+
for (const json of results) {
|
|
9
|
+
const result = schema.safeParse(json);
|
|
10
|
+
if (result.success) {
|
|
11
|
+
validated.push(result.data);
|
|
12
|
+
}
|
|
9
13
|
}
|
|
10
|
-
|
|
11
|
-
return result.success ? result.data : null;
|
|
14
|
+
return validated;
|
|
12
15
|
}
|
|
13
16
|
//# sourceMappingURL=extractTyped.js.map
|
package/dist/extractTyped.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractTyped.js","sourceRoot":"","sources":["../src/extractTyped.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"extractTyped.js","sourceRoot":"","sources":["../src/extractTyped.ts"],"names":[],"mappings":";;AAYA,oCAcC;AA1BD,qDAA+C;AAY/C,SAAgB,YAAY,CAC1B,IAAY,EACZ,MAAqB,EACrB,QAAiB;IAEjB,MAAM,OAAO,GAAG,IAAA,4BAAW,EAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAQ,EAAE,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/dist/findBalanced.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findBalanced.d.ts","sourceRoot":"","sources":["../src/findBalanced.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CA6Cf"}
|
|
1
|
+
{"version":3,"file":"findBalanced.d.ts","sourceRoot":"","sources":["../src/findBalanced.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CA6Cf;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAiBV"}
|
package/dist/findBalanced.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.findBalanced = findBalanced;
|
|
4
|
+
exports.findAllBalanced = findAllBalanced;
|
|
4
5
|
function findBalanced(text, openChar, closeChar) {
|
|
5
6
|
const start = text.indexOf(openChar);
|
|
6
7
|
if (start === -1) {
|
|
@@ -40,4 +41,19 @@ function findBalanced(text, openChar, closeChar) {
|
|
|
40
41
|
}
|
|
41
42
|
return null;
|
|
42
43
|
}
|
|
44
|
+
function findAllBalanced(text, openChar, closeChar) {
|
|
45
|
+
const results = [];
|
|
46
|
+
let offset = 0;
|
|
47
|
+
while (offset < text.length) {
|
|
48
|
+
const remaining = text.slice(offset);
|
|
49
|
+
const match = findBalanced(remaining, openChar, closeChar);
|
|
50
|
+
if (match === null) {
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
results.push(match);
|
|
54
|
+
const matchStart = remaining.indexOf(openChar);
|
|
55
|
+
offset += matchStart + match.length;
|
|
56
|
+
}
|
|
57
|
+
return results;
|
|
58
|
+
}
|
|
43
59
|
//# sourceMappingURL=findBalanced.js.map
|
package/dist/findBalanced.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findBalanced.js","sourceRoot":"","sources":["../src/findBalanced.ts"],"names":[],"mappings":";;AAAA,oCAiDC;
|
|
1
|
+
{"version":3,"file":"findBalanced.js","sourceRoot":"","sources":["../src/findBalanced.ts"],"names":[],"mappings":";;AAAA,oCAiDC;AAED,0CAqBC;AAxED,SAAgB,YAAY,CAC1B,IAAY,EACZ,QAAgB,EAChB,SAAiB;IAEjB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEnB,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,GAAG,KAAK,CAAC;YAChB,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YAChB,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,GAAG,IAAI,CAAC;YACjB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,QAAQ,GAAG,CAAC,QAAQ,CAAC;YACrB,SAAS;QACX,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;YACpB,KAAK,EAAE,CAAC;QACV,CAAC;aAAM,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YAC5B,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAgB,eAAe,CAC7B,IAAY,EACZ,QAAgB,EAChB,SAAiB;IAEjB,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,OAAO,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC3D,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,MAAM;QACR,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpB,MAAM,UAAU,GAAG,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/C,MAAM,IAAI,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC;IACtC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { extractCodeBlock } from "./extractCodeBlock.js";
|
|
2
2
|
export { extractJson } from "./extractJson.js";
|
|
3
|
-
export { extractTyped } from "./extractTyped.js";
|
|
3
|
+
export { extractTyped, type SchemaLike } from "./extractTyped.js";
|
|
4
|
+
export { extractTextContent, toPlainTextMessages, type MultimodalMessage, } from "./multimodal.js";
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,KAAK,iBAAiB,GACvB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractTyped = exports.extractJson = exports.extractCodeBlock = void 0;
|
|
3
|
+
exports.toPlainTextMessages = exports.extractTextContent = exports.extractTyped = exports.extractJson = exports.extractCodeBlock = void 0;
|
|
4
4
|
var extractCodeBlock_js_1 = require("./extractCodeBlock.js");
|
|
5
5
|
Object.defineProperty(exports, "extractCodeBlock", { enumerable: true, get: function () { return extractCodeBlock_js_1.extractCodeBlock; } });
|
|
6
6
|
var extractJson_js_1 = require("./extractJson.js");
|
|
7
7
|
Object.defineProperty(exports, "extractJson", { enumerable: true, get: function () { return extractJson_js_1.extractJson; } });
|
|
8
8
|
var extractTyped_js_1 = require("./extractTyped.js");
|
|
9
9
|
Object.defineProperty(exports, "extractTyped", { enumerable: true, get: function () { return extractTyped_js_1.extractTyped; } });
|
|
10
|
+
var multimodal_js_1 = require("./multimodal.js");
|
|
11
|
+
Object.defineProperty(exports, "extractTextContent", { enumerable: true, get: function () { return multimodal_js_1.extractTextContent; } });
|
|
12
|
+
Object.defineProperty(exports, "toPlainTextMessages", { enumerable: true, get: function () { return multimodal_js_1.toPlainTextMessages; } });
|
|
10
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6DAAyD;AAAhD,uHAAA,gBAAgB,OAAA;AACzB,mDAA+C;AAAtC,6GAAA,WAAW,OAAA;AACpB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6DAAyD;AAAhD,uHAAA,gBAAgB,OAAA;AACzB,mDAA+C;AAAtC,6GAAA,WAAW,OAAA;AACpB,qDAAkE;AAAzD,+GAAA,YAAY,OAAA;AACrB,iDAIyB;AAHvB,mHAAA,kBAAkB,OAAA;AAClB,oHAAA,mBAAmB,OAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structural type for messages that may contain multimodal content.
|
|
3
|
+
* Compatible with AI SDK message formats and ChatMessage from @ai/shared.
|
|
4
|
+
*/
|
|
5
|
+
export interface MultimodalMessage {
|
|
6
|
+
role: "system" | "user" | "assistant";
|
|
7
|
+
content: string | {
|
|
8
|
+
type: string;
|
|
9
|
+
text?: string;
|
|
10
|
+
}[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Extract text content from a message content field.
|
|
14
|
+
* Handles both plain string and multimodal content arrays.
|
|
15
|
+
*/
|
|
16
|
+
export declare function extractTextContent(content: MultimodalMessage["content"]): string;
|
|
17
|
+
/**
|
|
18
|
+
* Convert multimodal messages to plain text messages.
|
|
19
|
+
* Flattens any multimodal content arrays to plain text strings.
|
|
20
|
+
*/
|
|
21
|
+
export declare function toPlainTextMessages(messages: MultimodalMessage[]): {
|
|
22
|
+
role: "system" | "user" | "assistant";
|
|
23
|
+
content: string;
|
|
24
|
+
}[];
|
|
25
|
+
//# sourceMappingURL=multimodal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multimodal.d.ts","sourceRoot":"","sources":["../src/multimodal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,OAAO,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACrD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,iBAAiB,CAAC,SAAS,CAAC,GACpC,MAAM,CAWR;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,iBAAiB,EAAE,GAC5B;IAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,CAK9D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractTextContent = extractTextContent;
|
|
4
|
+
exports.toPlainTextMessages = toPlainTextMessages;
|
|
5
|
+
/**
|
|
6
|
+
* Extract text content from a message content field.
|
|
7
|
+
* Handles both plain string and multimodal content arrays.
|
|
8
|
+
*/
|
|
9
|
+
function extractTextContent(content) {
|
|
10
|
+
if (typeof content === "string") {
|
|
11
|
+
return content;
|
|
12
|
+
}
|
|
13
|
+
return content
|
|
14
|
+
.filter((c) => c.type === "text" && typeof c.text === "string")
|
|
15
|
+
.map((c) => c.text)
|
|
16
|
+
.join("\n");
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Convert multimodal messages to plain text messages.
|
|
20
|
+
* Flattens any multimodal content arrays to plain text strings.
|
|
21
|
+
*/
|
|
22
|
+
function toPlainTextMessages(messages) {
|
|
23
|
+
return messages.map((m) => ({
|
|
24
|
+
role: m.role,
|
|
25
|
+
content: extractTextContent(m.content),
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=multimodal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multimodal.js","sourceRoot":"","sources":["../src/multimodal.ts"],"names":[],"mappings":";;AAaA,gDAaC;AAMD,kDAOC;AA9BD;;;GAGG;AACH,SAAgB,kBAAkB,CAChC,OAAqC;IAErC,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,OAAO,OAAO;SACX,MAAM,CACL,CAAC,CAAC,EAAuC,EAAE,CACzC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAClD;SACA,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SAClB,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CACjC,QAA6B;IAE7B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1B,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,OAAO,CAAC;KACvC,CAAC,CAAC,CAAC;AACN,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hardlydifficult/ai-msg",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -14,14 +14,6 @@
|
|
|
14
14
|
"lint": "tsc --noEmit",
|
|
15
15
|
"clean": "rm -rf dist"
|
|
16
16
|
},
|
|
17
|
-
"peerDependencies": {
|
|
18
|
-
"zod": ">=3.0.0"
|
|
19
|
-
},
|
|
20
|
-
"peerDependenciesMeta": {
|
|
21
|
-
"zod": {
|
|
22
|
-
"optional": true
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
17
|
"devDependencies": {
|
|
26
18
|
"typescript": "5.8.3",
|
|
27
19
|
"vitest": "1.6.1",
|