@hardlydifficult/ai-msg 1.0.1 → 1.0.3
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 +34 -50
- package/dist/extractCodeBlock.d.ts +1 -0
- package/dist/extractCodeBlock.d.ts.map +1 -1
- package/dist/extractCodeBlock.js +1 -0
- package/dist/extractCodeBlock.js.map +1 -1
- package/dist/extractJson.d.ts +1 -0
- package/dist/extractJson.d.ts.map +1 -1
- package/dist/extractJson.js +1 -0
- package/dist/extractJson.js.map +1 -1
- package/dist/extractTyped.d.ts +15 -2
- package/dist/extractTyped.d.ts.map +1 -1
- package/dist/extractTyped.js +1 -0
- package/dist/extractTyped.js.map +1 -1
- package/dist/findBalanced.d.ts +2 -0
- package/dist/findBalanced.d.ts.map +1 -1
- package/dist/findBalanced.js +2 -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,60 +8,51 @@ 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
|
-
```
|
|
18
|
-
|
|
19
|
-
## Usage
|
|
11
|
+
## API
|
|
20
12
|
|
|
21
|
-
### `extractJson(text, sentinel
|
|
13
|
+
### `extractJson(text: string, sentinel?: string): unknown[]`
|
|
22
14
|
|
|
23
|
-
|
|
15
|
+
Extract JSON objects/arrays from AI response text. Uses a three-pass strategy:
|
|
24
16
|
|
|
25
|
-
1.
|
|
26
|
-
2.
|
|
27
|
-
3. Find
|
|
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
|
|
28
20
|
|
|
29
|
-
|
|
21
|
+
Pass a `sentinel` string to return `[]` when the response contains it (useful for "no results" markers).
|
|
30
22
|
|
|
31
23
|
````typescript
|
|
32
24
|
import { extractJson } from "@hardlydifficult/ai-msg";
|
|
33
25
|
|
|
34
|
-
extractJson('{"key": "value"}');
|
|
35
|
-
// [{ key: "value" }]
|
|
36
|
-
|
|
37
26
|
extractJson('Here is the result:\n```json\n{"key": "value"}\n```\nDone.');
|
|
38
27
|
// [{ key: "value" }]
|
|
39
28
|
|
|
40
|
-
extractJson('
|
|
41
|
-
// [{
|
|
29
|
+
extractJson('First {"a": 1} then {"b": 2} done.');
|
|
30
|
+
// [{ a: 1 }, { b: 2 }]
|
|
42
31
|
|
|
43
|
-
extractJson("
|
|
32
|
+
extractJson("NO_FINDINGS: scan completed.", "NO_FINDINGS");
|
|
44
33
|
// []
|
|
45
34
|
````
|
|
46
35
|
|
|
47
|
-
|
|
36
|
+
### `extractTyped<T>(text: string, schema: SchemaLike<T>, sentinel?: string): T[]`
|
|
37
|
+
|
|
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
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
```
|
|
41
|
+
import { extractTyped } from "@hardlydifficult/ai-msg";
|
|
42
|
+
import { z } from "zod";
|
|
53
43
|
|
|
54
|
-
|
|
44
|
+
const Person = z.object({ name: z.string(), age: z.number() });
|
|
55
45
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// []
|
|
46
|
+
extractTyped('{"name": "Alice", "age": 30}', Person);
|
|
47
|
+
// [{ name: "Alice", age: 30 }]
|
|
59
48
|
|
|
60
|
-
|
|
61
|
-
// [
|
|
49
|
+
extractTyped('{"name": "Alice", "age": "thirty"}', Person);
|
|
50
|
+
// [] — fails validation
|
|
62
51
|
```
|
|
63
52
|
|
|
64
|
-
### `extractCodeBlock(text, lang
|
|
53
|
+
### `extractCodeBlock(text: string, lang?: string): string[]`
|
|
65
54
|
|
|
66
|
-
|
|
55
|
+
Extract fenced code block contents. Optionally filter by language tag.
|
|
67
56
|
|
|
68
57
|
````typescript
|
|
69
58
|
import { extractCodeBlock } from "@hardlydifficult/ai-msg";
|
|
@@ -73,27 +62,22 @@ extractCodeBlock("```ts\nconst x = 1;\n```");
|
|
|
73
62
|
|
|
74
63
|
extractCodeBlock("```json\n{}\n```\n```ts\nconst x = 1;\n```", "json");
|
|
75
64
|
// ["{}"]
|
|
76
|
-
|
|
77
|
-
extractCodeBlock("no code blocks");
|
|
78
|
-
// []
|
|
79
65
|
````
|
|
80
66
|
|
|
81
|
-
### `
|
|
67
|
+
### `extractTextContent(content: string | { type: string; text?: string }[]): string`
|
|
82
68
|
|
|
83
|
-
|
|
69
|
+
Extract plain text from a message content field. Handles both plain strings and multimodal content arrays (AI SDK format).
|
|
84
70
|
|
|
85
71
|
```typescript
|
|
86
|
-
import {
|
|
87
|
-
import { z } from "zod";
|
|
72
|
+
import { extractTextContent } from "@hardlydifficult/ai-msg";
|
|
88
73
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
74
|
+
extractTextContent("hello"); // "hello"
|
|
75
|
+
extractTextContent([
|
|
76
|
+
{ type: "text", text: "hello" },
|
|
77
|
+
{ type: "image_url", url: "..." },
|
|
78
|
+
]); // "hello"
|
|
79
|
+
```
|
|
93
80
|
|
|
94
|
-
|
|
95
|
-
// []
|
|
81
|
+
### `toPlainTextMessages(messages: MultimodalMessage[]): { role, content }[]`
|
|
96
82
|
|
|
97
|
-
|
|
98
|
-
// []
|
|
99
|
-
```
|
|
83
|
+
Convert multimodal messages to plain text messages by flattening content arrays.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractCodeBlock.d.ts","sourceRoot":"","sources":["../src/extractCodeBlock.ts"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAatE"}
|
|
1
|
+
{"version":3,"file":"extractCodeBlock.d.ts","sourceRoot":"","sources":["../src/extractCodeBlock.ts"],"names":[],"mappings":"AAEA,sGAAsG;AACtG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAatE"}
|
package/dist/extractCodeBlock.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractCodeBlock = extractCodeBlock;
|
|
4
4
|
const codeBlockRegex = /^```(\w*)\s*\n([\s\S]*?)^```/gm;
|
|
5
|
+
/** Extracts the contents of fenced code blocks from a string, optionally filtered by language tag. */
|
|
5
6
|
function extractCodeBlock(text, lang) {
|
|
6
7
|
const results = [];
|
|
7
8
|
for (const match of text.matchAll(codeBlockRegex)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractCodeBlock.js","sourceRoot":"","sources":["../src/extractCodeBlock.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"extractCodeBlock.js","sourceRoot":"","sources":["../src/extractCodeBlock.ts"],"names":[],"mappings":";;AAGA,4CAaC;AAhBD,MAAM,cAAc,GAAG,gCAAgC,CAAC;AAExD,sGAAsG;AACtG,SAAgB,gBAAgB,CAAC,IAAY,EAAE,IAAa;IAC1D,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACnE,SAAS;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/dist/extractJson.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
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"}
|
|
1
|
+
{"version":3,"file":"extractJson.d.ts","sourceRoot":"","sources":["../src/extractJson.ts"],"names":[],"mappings":"AAWA,4HAA4H;AAC5H,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAgDtE"}
|
package/dist/extractJson.js
CHANGED
|
@@ -11,6 +11,7 @@ function tryParse(text) {
|
|
|
11
11
|
return undefined;
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
/** Extracts JSON values from text using progressive strategies: direct parse, code blocks, then balanced-brace scanning. */
|
|
14
15
|
function extractJson(text, sentinel) {
|
|
15
16
|
// Sentinel check — if the text contains the sentinel, treat as "no findings"
|
|
16
17
|
if (sentinel !== undefined && text.includes(sentinel)) {
|
package/dist/extractJson.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractJson.js","sourceRoot":"","sources":["../src/extractJson.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"extractJson.js","sourceRoot":"","sources":["../src/extractJson.ts"],"names":[],"mappings":";;AAYA,kCAgDC;AA5DD,+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,4HAA4H;AAC5H,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,16 @@
|
|
|
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
|
+
/** Extracts JSON from text and validates each result against a schema, returning only values that pass. */
|
|
15
|
+
export declare function extractTyped<T>(text: string, schema: SchemaLike<T>, sentinel?: string): T[];
|
|
3
16
|
//# 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,2GAA2G;AAC3G,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,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractTyped = extractTyped;
|
|
4
4
|
const extractJson_js_1 = require("./extractJson.js");
|
|
5
|
+
/** Extracts JSON from text and validates each result against a schema, returning only values that pass. */
|
|
5
6
|
function extractTyped(text, schema, sentinel) {
|
|
6
7
|
const results = (0, extractJson_js_1.extractJson)(text, sentinel);
|
|
7
8
|
const validated = [];
|
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":";;AAaA,oCAcC;AA3BD,qDAA+C;AAY/C,2GAA2G;AAC3G,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,3 +1,5 @@
|
|
|
1
|
+
/** Finds the first substring enclosed by balanced open/close characters, respecting JSON string escaping. */
|
|
1
2
|
export declare function findBalanced(text: string, openChar: string, closeChar: string): string | null;
|
|
3
|
+
/** Finds all non-overlapping substrings enclosed by balanced open/close characters. */
|
|
2
4
|
export declare function findAllBalanced(text: string, openChar: string, closeChar: string): string[];
|
|
3
5
|
//# sourceMappingURL=findBalanced.d.ts.map
|
|
@@ -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;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAiBV"}
|
|
1
|
+
{"version":3,"file":"findBalanced.d.ts","sourceRoot":"","sources":["../src/findBalanced.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CA6Cf;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,MAAM,EAAE,CAiBV"}
|
package/dist/findBalanced.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.findBalanced = findBalanced;
|
|
4
4
|
exports.findAllBalanced = findAllBalanced;
|
|
5
|
+
/** Finds the first substring enclosed by balanced open/close characters, respecting JSON string escaping. */
|
|
5
6
|
function findBalanced(text, openChar, closeChar) {
|
|
6
7
|
const start = text.indexOf(openChar);
|
|
7
8
|
if (start === -1) {
|
|
@@ -41,6 +42,7 @@ function findBalanced(text, openChar, closeChar) {
|
|
|
41
42
|
}
|
|
42
43
|
return null;
|
|
43
44
|
}
|
|
45
|
+
/** Finds all non-overlapping substrings enclosed by balanced open/close characters. */
|
|
44
46
|
function findAllBalanced(text, openChar, closeChar) {
|
|
45
47
|
const results = [];
|
|
46
48
|
let offset = 0;
|
package/dist/findBalanced.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"findBalanced.js","sourceRoot":"","sources":["../src/findBalanced.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"findBalanced.js","sourceRoot":"","sources":["../src/findBalanced.ts"],"names":[],"mappings":";;AACA,oCAiDC;AAGD,0CAqBC;AA1ED,6GAA6G;AAC7G,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,uFAAuF;AACvF,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.3",
|
|
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",
|