@molecule/api-agent-transcript-markdown-chat 1.0.0 → 1.0.1
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 +167 -0
- package/dist/chat.d.ts +47 -0
- package/dist/chat.d.ts.map +1 -0
- package/dist/chat.js +148 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/provider.d.ts +12 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +23 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
3
|
+
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
|
+
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
|
+
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
+
Generated: 2026-09-29T16:49:58.176Z
|
|
7
|
+
-->
|
|
8
|
+
|
|
9
|
+
# @molecule/api-agent-transcript-markdown-chat
|
|
10
|
+
|
|
11
|
+
> **Auto-generated, AI-first package reference** for the [molecule.dev](https://molecule.dev) ecosystem.
|
|
12
|
+
> It is written to be read by coding agents as much as by people, and is generated from this
|
|
13
|
+
> package's source — edit `src/index.ts` JSDoc, not this file.
|
|
14
|
+
|
|
15
|
+
Generic Markdown chat reader for `@molecule/api-agent-transcript`.
|
|
16
|
+
|
|
17
|
+
The reader of last resort: a plain Markdown or text chat whose turns start
|
|
18
|
+
with a speaker marker — a heading (`## User` / `## Assistant`), a bold
|
|
19
|
+
label (`**User:** …`) or a plain label (`User: …`). Use it for chats saved
|
|
20
|
+
by hand, copied out of a chat web app, or written by a harness that has no
|
|
21
|
+
reader of its own.
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { readTranscript, setProvider } from '@molecule/api-agent-transcript'
|
|
27
|
+
import { provider } from '@molecule/api-agent-transcript-markdown-chat'
|
|
28
|
+
|
|
29
|
+
setProvider(provider)
|
|
30
|
+
const session = readTranscript({
|
|
31
|
+
text: '**User:** Add a README.\n\n**Assistant:** Added README.md with a short overview.',
|
|
32
|
+
fileName: 'chat.md',
|
|
33
|
+
})
|
|
34
|
+
// session.turns → [{ role: 'user', … }, { role: 'assistant', … }]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Type
|
|
38
|
+
|
|
39
|
+
`provider`
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install @molecule/api-agent-transcript-markdown-chat @molecule/api-agent-transcript
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## API
|
|
48
|
+
|
|
49
|
+
### Functions
|
|
50
|
+
|
|
51
|
+
#### `chatStyleOf(text)`
|
|
52
|
+
|
|
53
|
+
The marker style a text uses: the style of its first marker, provided the
|
|
54
|
+
text has at least one user and one assistant marker in that style.
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
function chatStyleOf(text: string): Style | null
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- `text` — The text.
|
|
61
|
+
|
|
62
|
+
**Returns:** The style, or `null` when the text is not a chat.
|
|
63
|
+
|
|
64
|
+
#### `looksLikeMarkdownChat(text)`
|
|
65
|
+
|
|
66
|
+
Whether a text is a Markdown / plain-text chat.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
function looksLikeMarkdownChat(text: string): boolean
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- `text` — The file's text.
|
|
73
|
+
|
|
74
|
+
**Returns:** True when it has user and assistant markers in one style.
|
|
75
|
+
|
|
76
|
+
#### `readMarkdownChat(text)`
|
|
77
|
+
|
|
78
|
+
Read a Markdown / plain-text chat.
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
function readMarkdownChat(text: string): AgentSession
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- `text` — The chat's text.
|
|
85
|
+
|
|
86
|
+
**Returns:** The normalized session.
|
|
87
|
+
|
|
88
|
+
### Constants
|
|
89
|
+
|
|
90
|
+
#### `ASSISTANT_NAMES`
|
|
91
|
+
|
|
92
|
+
Names that mark the assistant.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
const ASSISTANT_NAMES: readonly [
|
|
96
|
+
'assistant',
|
|
97
|
+
'ai',
|
|
98
|
+
'bot',
|
|
99
|
+
'model',
|
|
100
|
+
'agent',
|
|
101
|
+
'claude',
|
|
102
|
+
'chatgpt',
|
|
103
|
+
'gpt',
|
|
104
|
+
'gemini',
|
|
105
|
+
'copilot',
|
|
106
|
+
'cursor',
|
|
107
|
+
]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### `provider`
|
|
111
|
+
|
|
112
|
+
Reads a plain Markdown or text chat with User / Assistant speaker markers.
|
|
113
|
+
Compose it LAST: every harness-specific reader should get the first look.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const provider: AgentTranscriptReader
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### `USER_NAMES`
|
|
120
|
+
|
|
121
|
+
Names that mark the person.
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
const USER_NAMES: readonly ['user', 'human', 'you', 'me']
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Core Interface
|
|
128
|
+
|
|
129
|
+
Implements `@molecule/api-agent-transcript` interface.
|
|
130
|
+
|
|
131
|
+
## Bond Wiring
|
|
132
|
+
|
|
133
|
+
Setup function to register this provider with the core interface:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { setProvider } from '@molecule/api-agent-transcript'
|
|
137
|
+
import { provider } from '@molecule/api-agent-transcript-markdown-chat'
|
|
138
|
+
|
|
139
|
+
export function setupAgentTranscriptMarkdownChat(): void {
|
|
140
|
+
setProvider(provider)
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Injection Notes
|
|
145
|
+
|
|
146
|
+
### Requirements
|
|
147
|
+
|
|
148
|
+
Peer dependencies:
|
|
149
|
+
|
|
150
|
+
- `@molecule/api-agent-transcript` ^1.0.0
|
|
151
|
+
|
|
152
|
+
### Runtime Dependencies
|
|
153
|
+
|
|
154
|
+
- `@molecule/api-agent-transcript`
|
|
155
|
+
|
|
156
|
+
- **Compose it last.** `@molecule/api-agent-transcript-autodetect` tries
|
|
157
|
+
every harness reader first; this one only sees files none of them claimed.
|
|
158
|
+
- It still refuses anything without at least one user marker AND one
|
|
159
|
+
assistant marker, so a document that merely mentions "User:" is not a chat.
|
|
160
|
+
- User names: User, Human, You, Me. Assistant names: Assistant, AI, Bot,
|
|
161
|
+
Model, Agent, Claude, ChatGPT, GPT, Gemini, Copilot, Cursor. Case does not
|
|
162
|
+
matter; a trailing colon is optional for headings.
|
|
163
|
+
- Only the style of the file's first marker splits turns, and markers
|
|
164
|
+
inside fenced code blocks are ignored — so a `Model:` line in a reply
|
|
165
|
+
does not break a chat written with `##` headings.
|
|
166
|
+
- A chat names no model, no times and no file writes; those fields stay
|
|
167
|
+
empty. `harness` is `Markdown chat`.
|
package/dist/chat.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A plain Markdown or text chat: turns introduced by a speaker marker in one
|
|
3
|
+
* of three styles — a heading (`## User`), a bold label (`**User:**`, text
|
|
4
|
+
* may follow on the same line) or a plain label at the start of a line
|
|
5
|
+
* (`User: …`).
|
|
6
|
+
*
|
|
7
|
+
* This is the reader of last resort, for chats saved by hand, by a harness
|
|
8
|
+
* with no reader of its own, or by a chat web app's copy button. It never
|
|
9
|
+
* guesses at a format: the file must hold at least one user marker AND one
|
|
10
|
+
* assistant marker, and only the style of the file's first marker splits
|
|
11
|
+
* turns, so a `Model:` line or `## Assistant notes` heading inside a reply
|
|
12
|
+
* cannot start a new turn in a file that uses another style. Markers inside
|
|
13
|
+
* fenced code blocks are ignored.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import type { AgentSession } from '@molecule/api-agent-transcript';
|
|
18
|
+
/** Names that mark the person. */
|
|
19
|
+
export declare const USER_NAMES: readonly ["user", "human", "you", "me"];
|
|
20
|
+
/** Names that mark the assistant. */
|
|
21
|
+
export declare const ASSISTANT_NAMES: readonly ["assistant", "ai", "bot", "model", "agent", "claude", "chatgpt", "gpt", "gemini", "copilot", "cursor"];
|
|
22
|
+
type Style = 'heading' | 'bold' | 'plain';
|
|
23
|
+
/**
|
|
24
|
+
* The marker style a text uses: the style of its first marker, provided the
|
|
25
|
+
* text has at least one user and one assistant marker in that style.
|
|
26
|
+
*
|
|
27
|
+
* @param text - The text.
|
|
28
|
+
* @returns The style, or `null` when the text is not a chat.
|
|
29
|
+
*/
|
|
30
|
+
export declare function chatStyleOf(text: string): Style | null;
|
|
31
|
+
/**
|
|
32
|
+
* Whether a text is a Markdown / plain-text chat.
|
|
33
|
+
*
|
|
34
|
+
* @param text - The file's text.
|
|
35
|
+
* @returns True when it has user and assistant markers in one style.
|
|
36
|
+
*/
|
|
37
|
+
export declare function looksLikeMarkdownChat(text: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Read a Markdown / plain-text chat.
|
|
40
|
+
*
|
|
41
|
+
* @param text - The chat's text.
|
|
42
|
+
* @returns The normalized session.
|
|
43
|
+
* @throws {Error} When the text is not a chat.
|
|
44
|
+
*/
|
|
45
|
+
export declare function readMarkdownChat(text: string): AgentSession;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=chat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../src/chat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,gCAAgC,CAAA;AAE5F,kCAAkC;AAClC,eAAO,MAAM,UAAU,yCAA0C,CAAA;AAEjE,qCAAqC;AACrC,eAAO,MAAM,eAAe,kHAYlB,CAAA;AAEV,KAAK,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAA;AA2DzC;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAMtD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CA4B3D"}
|
package/dist/chat.js
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A plain Markdown or text chat: turns introduced by a speaker marker in one
|
|
3
|
+
* of three styles — a heading (`## User`), a bold label (`**User:**`, text
|
|
4
|
+
* may follow on the same line) or a plain label at the start of a line
|
|
5
|
+
* (`User: …`).
|
|
6
|
+
*
|
|
7
|
+
* This is the reader of last resort, for chats saved by hand, by a harness
|
|
8
|
+
* with no reader of its own, or by a chat web app's copy button. It never
|
|
9
|
+
* guesses at a format: the file must hold at least one user marker AND one
|
|
10
|
+
* assistant marker, and only the style of the file's first marker splits
|
|
11
|
+
* turns, so a `Model:` line or `## Assistant notes` heading inside a reply
|
|
12
|
+
* cannot start a new turn in a file that uses another style. Markers inside
|
|
13
|
+
* fenced code blocks are ignored.
|
|
14
|
+
*
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
/** Names that mark the person. */
|
|
18
|
+
export const USER_NAMES = ['user', 'human', 'you', 'me'];
|
|
19
|
+
/** Names that mark the assistant. */
|
|
20
|
+
export const ASSISTANT_NAMES = [
|
|
21
|
+
'assistant',
|
|
22
|
+
'ai',
|
|
23
|
+
'bot',
|
|
24
|
+
'model',
|
|
25
|
+
'agent',
|
|
26
|
+
'claude',
|
|
27
|
+
'chatgpt',
|
|
28
|
+
'gpt',
|
|
29
|
+
'gemini',
|
|
30
|
+
'copilot',
|
|
31
|
+
'cursor',
|
|
32
|
+
];
|
|
33
|
+
const NAME = `(${[...USER_NAMES, ...ASSISTANT_NAMES].join('|')})`;
|
|
34
|
+
const PATTERNS = {
|
|
35
|
+
heading: new RegExp(`^#{1,4}\\s+${NAME}\\s*:?\\s*$`, 'i'),
|
|
36
|
+
bold: new RegExp(`^\\*\\*${NAME}(?::\\*\\*|\\*\\*:?)\\s*(.*)$`, 'i'),
|
|
37
|
+
plain: new RegExp(`^${NAME}:\\s*(.*)$`, 'i'),
|
|
38
|
+
};
|
|
39
|
+
const STYLES = ['heading', 'bold', 'plain'];
|
|
40
|
+
/**
|
|
41
|
+
* The speaker marker on a line, if any.
|
|
42
|
+
*
|
|
43
|
+
* @param line - The line.
|
|
44
|
+
* @param only - Only this style counts, when given.
|
|
45
|
+
* @returns The marker, or `null`.
|
|
46
|
+
*/
|
|
47
|
+
function markerOf(line, only) {
|
|
48
|
+
for (const style of only ? [only] : STYLES) {
|
|
49
|
+
const m = PATTERNS[style].exec(line);
|
|
50
|
+
if (!m)
|
|
51
|
+
continue;
|
|
52
|
+
const name = m[1].toLowerCase();
|
|
53
|
+
const role = USER_NAMES.includes(name)
|
|
54
|
+
? 'user'
|
|
55
|
+
: 'assistant';
|
|
56
|
+
return { style, role, rest: (m[2] ?? '').trim() };
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The lines outside fenced code blocks, with their fence state.
|
|
62
|
+
*
|
|
63
|
+
* @param text - The text.
|
|
64
|
+
* @returns Each line and whether it is inside a fence.
|
|
65
|
+
*/
|
|
66
|
+
function withFences(text) {
|
|
67
|
+
let fence = null;
|
|
68
|
+
return text
|
|
69
|
+
.replace(/\r\n?/g, '\n')
|
|
70
|
+
.split('\n')
|
|
71
|
+
.map((line) => {
|
|
72
|
+
const f = /^\s*(`{3,}|~{3,})/.exec(line);
|
|
73
|
+
const wasFenced = fence !== null;
|
|
74
|
+
if (f) {
|
|
75
|
+
if (fence === null)
|
|
76
|
+
fence = f[1][0];
|
|
77
|
+
else if (f[1][0] === fence)
|
|
78
|
+
fence = null;
|
|
79
|
+
}
|
|
80
|
+
return { line, fenced: wasFenced || !!f };
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* The marker style a text uses: the style of its first marker, provided the
|
|
85
|
+
* text has at least one user and one assistant marker in that style.
|
|
86
|
+
*
|
|
87
|
+
* @param text - The text.
|
|
88
|
+
* @returns The style, or `null` when the text is not a chat.
|
|
89
|
+
*/
|
|
90
|
+
export function chatStyleOf(text) {
|
|
91
|
+
const lines = withFences(text).filter((l) => !l.fenced);
|
|
92
|
+
const first = lines.map((l) => markerOf(l.line)).find(Boolean);
|
|
93
|
+
if (!first)
|
|
94
|
+
return null;
|
|
95
|
+
const roles = new Set(lines.map((l) => markerOf(l.line, first.style)?.role).filter(Boolean));
|
|
96
|
+
return roles.has('user') && roles.has('assistant') ? first.style : null;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Whether a text is a Markdown / plain-text chat.
|
|
100
|
+
*
|
|
101
|
+
* @param text - The file's text.
|
|
102
|
+
* @returns True when it has user and assistant markers in one style.
|
|
103
|
+
*/
|
|
104
|
+
export function looksLikeMarkdownChat(text) {
|
|
105
|
+
return chatStyleOf(text) !== null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Read a Markdown / plain-text chat.
|
|
109
|
+
*
|
|
110
|
+
* @param text - The chat's text.
|
|
111
|
+
* @returns The normalized session.
|
|
112
|
+
* @throws {Error} When the text is not a chat.
|
|
113
|
+
*/
|
|
114
|
+
export function readMarkdownChat(text) {
|
|
115
|
+
const style = chatStyleOf(text);
|
|
116
|
+
if (!style)
|
|
117
|
+
throw new Error('Not a Markdown chat: no user and assistant speaker markers.');
|
|
118
|
+
const turns = [];
|
|
119
|
+
let current = null;
|
|
120
|
+
const close = () => {
|
|
121
|
+
if (!current)
|
|
122
|
+
return;
|
|
123
|
+
const body = current.body.join('\n').trim();
|
|
124
|
+
if (body) {
|
|
125
|
+
const last = turns[turns.length - 1];
|
|
126
|
+
if (last && last.role === current.role)
|
|
127
|
+
last.text = `${last.text}\n\n${body}`;
|
|
128
|
+
else
|
|
129
|
+
turns.push({ role: current.role, text: body, files: [] });
|
|
130
|
+
}
|
|
131
|
+
current = null;
|
|
132
|
+
};
|
|
133
|
+
for (const { line, fenced } of withFences(text)) {
|
|
134
|
+
const m = fenced ? null : markerOf(line, style);
|
|
135
|
+
if (m) {
|
|
136
|
+
close();
|
|
137
|
+
current = { role: m.role, body: m.rest ? [m.rest] : [] };
|
|
138
|
+
}
|
|
139
|
+
else if (current) {
|
|
140
|
+
current.body.push(line);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
close();
|
|
144
|
+
// A `---` rule between turns belongs to the file's layout, not the message.
|
|
145
|
+
for (const t of turns)
|
|
146
|
+
t.text = t.text.replace(/\n+-{3,}\s*$/, '').trim();
|
|
147
|
+
return { format: 'markdown-chat', harness: 'Markdown chat', turns };
|
|
148
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic Markdown chat reader for `@molecule/api-agent-transcript`.
|
|
3
|
+
*
|
|
4
|
+
* The reader of last resort: a plain Markdown or text chat whose turns start
|
|
5
|
+
* with a speaker marker — a heading (`## User` / `## Assistant`), a bold
|
|
6
|
+
* label (`**User:** …`) or a plain label (`User: …`). Use it for chats saved
|
|
7
|
+
* by hand, copied out of a chat web app, or written by a harness that has no
|
|
8
|
+
* reader of its own.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { readTranscript, setProvider } from '@molecule/api-agent-transcript'
|
|
13
|
+
* import { provider } from '@molecule/api-agent-transcript-markdown-chat'
|
|
14
|
+
*
|
|
15
|
+
* setProvider(provider)
|
|
16
|
+
* const session = readTranscript({
|
|
17
|
+
* text: '**User:** Add a README.\n\n**Assistant:** Added README.md with a short overview.',
|
|
18
|
+
* fileName: 'chat.md',
|
|
19
|
+
* })
|
|
20
|
+
* // session.turns → [{ role: 'user', … }, { role: 'assistant', … }]
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* - **Compose it last.** `@molecule/api-agent-transcript-autodetect` tries
|
|
25
|
+
* every harness reader first; this one only sees files none of them claimed.
|
|
26
|
+
* - It still refuses anything without at least one user marker AND one
|
|
27
|
+
* assistant marker, so a document that merely mentions "User:" is not a chat.
|
|
28
|
+
* - User names: User, Human, You, Me. Assistant names: Assistant, AI, Bot,
|
|
29
|
+
* Model, Agent, Claude, ChatGPT, GPT, Gemini, Copilot, Cursor. Case does not
|
|
30
|
+
* matter; a trailing colon is optional for headings.
|
|
31
|
+
* - Only the style of the file's first marker splits turns, and markers
|
|
32
|
+
* inside fenced code blocks are ignored — so a `Model:` line in a reply
|
|
33
|
+
* does not break a chat written with `##` headings.
|
|
34
|
+
* - A chat names no model, no times and no file writes; those fields stay
|
|
35
|
+
* empty. `harness` is `Markdown chat`.
|
|
36
|
+
*
|
|
37
|
+
* @module
|
|
38
|
+
*/
|
|
39
|
+
export * from './browser-guard.js';
|
|
40
|
+
export * from './chat.js';
|
|
41
|
+
export * from './provider.js';
|
|
42
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,cAAc,oBAAoB,CAAA;AAClC,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic Markdown chat reader for `@molecule/api-agent-transcript`.
|
|
3
|
+
*
|
|
4
|
+
* The reader of last resort: a plain Markdown or text chat whose turns start
|
|
5
|
+
* with a speaker marker — a heading (`## User` / `## Assistant`), a bold
|
|
6
|
+
* label (`**User:** …`) or a plain label (`User: …`). Use it for chats saved
|
|
7
|
+
* by hand, copied out of a chat web app, or written by a harness that has no
|
|
8
|
+
* reader of its own.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { readTranscript, setProvider } from '@molecule/api-agent-transcript'
|
|
13
|
+
* import { provider } from '@molecule/api-agent-transcript-markdown-chat'
|
|
14
|
+
*
|
|
15
|
+
* setProvider(provider)
|
|
16
|
+
* const session = readTranscript({
|
|
17
|
+
* text: '**User:** Add a README.\n\n**Assistant:** Added README.md with a short overview.',
|
|
18
|
+
* fileName: 'chat.md',
|
|
19
|
+
* })
|
|
20
|
+
* // session.turns → [{ role: 'user', … }, { role: 'assistant', … }]
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* @remarks
|
|
24
|
+
* - **Compose it last.** `@molecule/api-agent-transcript-autodetect` tries
|
|
25
|
+
* every harness reader first; this one only sees files none of them claimed.
|
|
26
|
+
* - It still refuses anything without at least one user marker AND one
|
|
27
|
+
* assistant marker, so a document that merely mentions "User:" is not a chat.
|
|
28
|
+
* - User names: User, Human, You, Me. Assistant names: Assistant, AI, Bot,
|
|
29
|
+
* Model, Agent, Claude, ChatGPT, GPT, Gemini, Copilot, Cursor. Case does not
|
|
30
|
+
* matter; a trailing colon is optional for headings.
|
|
31
|
+
* - Only the style of the file's first marker splits turns, and markers
|
|
32
|
+
* inside fenced code blocks are ignored — so a `Model:` line in a reply
|
|
33
|
+
* does not break a chat written with `##` headings.
|
|
34
|
+
* - A chat names no model, no times and no file writes; those fields stay
|
|
35
|
+
* empty. `harness` is `Markdown chat`.
|
|
36
|
+
*
|
|
37
|
+
* @module
|
|
38
|
+
*/
|
|
39
|
+
export * from './browser-guard.js';
|
|
40
|
+
export * from './chat.js';
|
|
41
|
+
export * from './provider.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generic Markdown / plain-text chat reader.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentTranscriptReader } from '@molecule/api-agent-transcript';
|
|
7
|
+
/**
|
|
8
|
+
* Reads a plain Markdown or text chat with User / Assistant speaker markers.
|
|
9
|
+
* Compose it LAST: every harness-specific reader should get the first look.
|
|
10
|
+
*/
|
|
11
|
+
export declare const provider: AgentTranscriptReader;
|
|
12
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,qBAAqB,EAEtB,MAAM,gCAAgC,CAAA;AAIvC;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,qBActB,CAAA"}
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generic Markdown / plain-text chat reader.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { looksLikeMarkdownChat, readMarkdownChat } from './chat.js';
|
|
7
|
+
/**
|
|
8
|
+
* Reads a plain Markdown or text chat with User / Assistant speaker markers.
|
|
9
|
+
* Compose it LAST: every harness-specific reader should get the first look.
|
|
10
|
+
*/
|
|
11
|
+
export const provider = {
|
|
12
|
+
format: 'markdown-chat',
|
|
13
|
+
label: 'Markdown chat',
|
|
14
|
+
detect(input) {
|
|
15
|
+
return looksLikeMarkdownChat(input.text);
|
|
16
|
+
},
|
|
17
|
+
read(input) {
|
|
18
|
+
if (!looksLikeMarkdownChat(input.text)) {
|
|
19
|
+
throw new Error(`Not a Markdown chat${input.fileName ? ` (${input.fileName})` : ''}: expected User and Assistant speaker markers (\`## User\`, \`**User:**\` or \`User:\`).`);
|
|
20
|
+
}
|
|
21
|
+
return readMarkdownChat(input.text);
|
|
22
|
+
},
|
|
23
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@molecule/api-agent-transcript-markdown-chat",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "A last-resort transcript reader for plain Markdown or text chats with clear User / Assistant speaker markers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|