@mercury-fw/core 0.26.0 → 0.27.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/CHANGELOG.md +19 -0
- package/dist/src/router/terminal.d.ts +7 -2
- package/package.json +5 -5
- package/src/router/terminal-provider.ts +12 -5
- package/src/router/terminal.ts +10 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @mercury-fw/core
|
|
2
2
|
|
|
3
|
+
## 0.27.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2c0e020: The REPL no longer prints the answer a second time, under "risposta corretta rispetto a quanto già mostrato sopra", after a turn that reasoned or called a tool.
|
|
8
|
+
- @mercury-fw/plugin-types@0.27.1
|
|
9
|
+
- @mercury-fw/channel-types@0.27.1
|
|
10
|
+
- @mercury-fw/cli-engine@0.27.1
|
|
11
|
+
- @mercury-fw/confirm-engine@0.27.1
|
|
12
|
+
|
|
13
|
+
## 0.27.0
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- @mercury-fw/plugin-types@0.27.0
|
|
18
|
+
- @mercury-fw/channel-types@0.27.0
|
|
19
|
+
- @mercury-fw/cli-engine@0.27.0
|
|
20
|
+
- @mercury-fw/confirm-engine@0.27.0
|
|
21
|
+
|
|
3
22
|
## 0.26.0
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
|
@@ -21,7 +21,10 @@ export declare const PROMPT = "> ";
|
|
|
21
21
|
* resolve. If `onChunk` is never called, the function's returned
|
|
22
22
|
* string is written instead once `handleInput` resolves, exactly as
|
|
23
23
|
* before streaming existed — this is what keeps the `/dump` command
|
|
24
|
-
* and any other non-streaming reply working unchanged.
|
|
24
|
+
* and any other non-streaming reply working unchanged. A chunk passed
|
|
25
|
+
* with `{ aside: true }` (reasoning, a tool label, a confirmation line)
|
|
26
|
+
* is written the same way but isn't part of the answer, so it's left out
|
|
27
|
+
* when the returned string is compared with what was streamed.
|
|
25
28
|
* @param io - Test seam. Defaults to real stdin/stdout when omitted.
|
|
26
29
|
* @param opts.promptSuffix - Optional, called fresh right before every
|
|
27
30
|
* prompt (including the very first one) and written ahead of it — e.g.
|
|
@@ -29,7 +32,9 @@ export declare const PROMPT = "> ";
|
|
|
29
32
|
* `formatContextUsage`), recomputed each time since the value changes
|
|
30
33
|
* turn to turn.
|
|
31
34
|
*/
|
|
32
|
-
export declare function startTerminalRepl(handleInput: (input: string, onChunk: (chunk: string
|
|
35
|
+
export declare function startTerminalRepl(handleInput: (input: string, onChunk: (chunk: string, opts?: {
|
|
36
|
+
aside?: boolean;
|
|
37
|
+
}) => void) => Promise<string>, io?: {
|
|
33
38
|
input?: AsyncIterable<string>;
|
|
34
39
|
output?: {
|
|
35
40
|
write(s: string, opts?: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mercury-fw/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"test": "bun test"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@mercury-fw/channel-types": "0.
|
|
35
|
-
"@mercury-fw/cli-engine": "0.
|
|
36
|
-
"@mercury-fw/confirm-engine": "0.
|
|
37
|
-
"@mercury-fw/plugin-types": "0.
|
|
34
|
+
"@mercury-fw/channel-types": "0.27.1",
|
|
35
|
+
"@mercury-fw/cli-engine": "0.27.1",
|
|
36
|
+
"@mercury-fw/confirm-engine": "0.27.1",
|
|
37
|
+
"@mercury-fw/plugin-types": "0.27.1",
|
|
38
38
|
"@qdrant/js-client-rest": "^1.19.0",
|
|
39
39
|
"ai": "^7.0.77",
|
|
40
40
|
"ai-sdk-ollama": "^4.2.0",
|
|
@@ -80,7 +80,10 @@ export function createTerminalProvider(deps: TerminalProviderDeps): Provider {
|
|
|
80
80
|
// seeing its result), each burst getting its own header/close
|
|
81
81
|
// rather than being mistaken for a continuation of the first.
|
|
82
82
|
const reasoningIdsStarted = new Set<string>();
|
|
83
|
-
|
|
83
|
+
// Everything but the answer text is an aside: printed as it comes,
|
|
84
|
+
// but not part of the answer the REPL compares with the result.
|
|
85
|
+
const aside = (chunk: string) => onChunk(chunk, { aside: true });
|
|
86
|
+
const dim = (label: string) => aside(`\x1b[2m\x1b[3m${label}\x1b[0m\n`);
|
|
84
87
|
const sink: TurnSink = {
|
|
85
88
|
onToolStart: dim,
|
|
86
89
|
// PENDING_CONFIRMATION_NOTE is dropped here: onStep (below)
|
|
@@ -99,10 +102,10 @@ export function createTerminalProvider(deps: TerminalProviderDeps): Provider {
|
|
|
99
102
|
reasoningIdsStarted.add(id);
|
|
100
103
|
dim("Sto pensando…");
|
|
101
104
|
}
|
|
102
|
-
|
|
105
|
+
aside(`\x1b[2m\x1b[3m${chunk}\x1b[0m`);
|
|
103
106
|
},
|
|
104
107
|
onReasoningEnd: (id) => {
|
|
105
|
-
if (reasoningIdsStarted.has(id))
|
|
108
|
+
if (reasoningIdsStarted.has(id)) aside("\n");
|
|
106
109
|
},
|
|
107
110
|
onStep: (step) => {
|
|
108
111
|
lastSteps.push(step);
|
|
@@ -111,7 +114,7 @@ export function createTerminalProvider(deps: TerminalProviderDeps): Provider {
|
|
|
111
114
|
// say it itself, from the structured step data.
|
|
112
115
|
const pending = detectPendingConfirmation(step);
|
|
113
116
|
if (pending) {
|
|
114
|
-
|
|
117
|
+
aside(`Azione in sospeso: \`${pending.summary}\` — scrivi: ${pending.token}\n`);
|
|
115
118
|
}
|
|
116
119
|
},
|
|
117
120
|
onUsage: (tokens) => {
|
|
@@ -140,7 +143,11 @@ export function createTerminalProvider(deps: TerminalProviderDeps): Provider {
|
|
|
140
143
|
if (contextLength === null) {
|
|
141
144
|
contextLength = await getLoadedContextLengthFn(deps.ollamaHost, deps.ollamaModel);
|
|
142
145
|
}
|
|
143
|
-
|
|
146
|
+
// The note's chunk was dropped above, so it isn't returned either,
|
|
147
|
+
// also when a surfaced display follows it.
|
|
148
|
+
return finalText.startsWith(PENDING_CONFIRMATION_NOTE)
|
|
149
|
+
? finalText.slice(PENDING_CONFIRMATION_NOTE.length).replace(/^\n\n/, "")
|
|
150
|
+
: finalText;
|
|
144
151
|
},
|
|
145
152
|
undefined,
|
|
146
153
|
{ promptSuffix: () => formatContextUsage(lastInputTokens, contextLength) },
|
package/src/router/terminal.ts
CHANGED
|
@@ -53,7 +53,10 @@ export const PROMPT = "> ";
|
|
|
53
53
|
* resolve. If `onChunk` is never called, the function's returned
|
|
54
54
|
* string is written instead once `handleInput` resolves, exactly as
|
|
55
55
|
* before streaming existed — this is what keeps the `/dump` command
|
|
56
|
-
* and any other non-streaming reply working unchanged.
|
|
56
|
+
* and any other non-streaming reply working unchanged. A chunk passed
|
|
57
|
+
* with `{ aside: true }` (reasoning, a tool label, a confirmation line)
|
|
58
|
+
* is written the same way but isn't part of the answer, so it's left out
|
|
59
|
+
* when the returned string is compared with what was streamed.
|
|
57
60
|
* @param io - Test seam. Defaults to real stdin/stdout when omitted.
|
|
58
61
|
* @param opts.promptSuffix - Optional, called fresh right before every
|
|
59
62
|
* prompt (including the very first one) and written ahead of it — e.g.
|
|
@@ -62,7 +65,7 @@ export const PROMPT = "> ";
|
|
|
62
65
|
* turn to turn.
|
|
63
66
|
*/
|
|
64
67
|
export async function startTerminalRepl(
|
|
65
|
-
handleInput: (input: string, onChunk: (chunk: string) => void) => Promise<string>,
|
|
68
|
+
handleInput: (input: string, onChunk: (chunk: string, opts?: { aside?: boolean }) => void) => Promise<string>,
|
|
66
69
|
io?: {
|
|
67
70
|
input?: AsyncIterable<string>;
|
|
68
71
|
output?: { write(s: string, opts?: { newline?: boolean }): void };
|
|
@@ -115,9 +118,9 @@ export async function startTerminalRepl(
|
|
|
115
118
|
for await (const line of input) {
|
|
116
119
|
let streamed = false;
|
|
117
120
|
let streamedText = "";
|
|
118
|
-
const onChunk = (chunk: string) => {
|
|
121
|
+
const onChunk = (chunk: string, chunkOpts?: { aside?: boolean }) => {
|
|
119
122
|
streamed = true;
|
|
120
|
-
streamedText += chunk;
|
|
123
|
+
if (!chunkOpts?.aside) streamedText += chunk;
|
|
121
124
|
output.write(chunk, { newline: false });
|
|
122
125
|
};
|
|
123
126
|
try {
|
|
@@ -132,9 +135,9 @@ export async function startTerminalRepl(
|
|
|
132
135
|
// needs writing.
|
|
133
136
|
output.write(result.slice(streamedText.length));
|
|
134
137
|
} else {
|
|
135
|
-
// The final result no longer extends what was already streamed
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
+
// The final result no longer extends what was already streamed:
|
|
139
|
+
// a plugin's post-turn guard (turn-runner.ts) rewrote the text
|
|
140
|
+
// after it was streamed. What's already printed
|
|
138
141
|
// can't be un-printed, so show the real final answer in full
|
|
139
142
|
// instead of a slice computed against text that isn't there
|
|
140
143
|
// anymore.
|