@@ -21,6 +21,7 @@ import (
21
21
"slices"
22
22
"strconv"
23
23
"strings"
24
+ "sync"
24
25
"time"
25
26
"unicode/utf8"
26
27
@@ -29,13 +30,14 @@ import (
29
30
"github.com/aws/aws-sdk-go-v2/service/bedrockruntime"
30
31
"github.com/aws/aws-sdk-go-v2/service/bedrockruntime/document"
31
32
"github.com/aws/aws-sdk-go-v2/service/bedrockruntime/types"
33
+ "golang.org/x/term"
32
34
"rsc.io/markdown"
33
35
)
34
36
35
37
func main () {
36
38
log .SetFlags (0 )
37
39
log .SetPrefix ("llmcli: " )
38
- if st , err := os .Stderr .Stat (); err == nil && st . Mode () & os . ModeCharDevice != 0 {
40
+ if term . IsTerminal ( int ( os .Stderr .Fd ())) {
39
41
log .SetPrefix ("\033 [1m" + log .Prefix () + ansiReset )
40
42
}
41
43
args := runArgs {model : os .Getenv ("LLMCLI_MODEL" )}
@@ -200,16 +202,16 @@ func run(ctx context.Context, args runArgs) error {
200
202
if args .budget != 0 {
201
203
// just in case we changed stdout formatting at the start of “thinking”
202
204
// but failed mid-way before resetting formatting
203
- defer os . Stdout . WriteString (ansiReset )
205
+ defer termWrite (ansiReset )
204
206
}
205
207
var thinking bool
206
208
for chunk := range rc .Chunks () {
207
209
if ! thinking && chunk .thinking {
208
210
thinking = true
209
- os . Stdout . WriteString (ansiItalic ) // bypassing wr
211
+ termWrite (ansiItalic ) // bypassing wr
210
212
} else if thinking && ! chunk .thinking {
211
213
thinking = false
212
- os . Stdout . WriteString (ansiReset ) // bypassing wr
214
+ termWrite (ansiReset ) // bypassing wr
213
215
io .WriteString (wr , "\n \n * * *\n \n " )
214
216
}
215
217
io .WriteString (wr , chunk .text )
@@ -226,6 +228,15 @@ func run(ctx context.Context, args runArgs) error {
226
228
return nil
227
229
}
228
230
231
+ var stdoutIsTerm = sync .OnceValue (func () bool { return term .IsTerminal (int (os .Stdout .Fd ())) })
232
+
233
+ func termWrite (s string ) {
234
+ if ! stdoutIsTerm () {
235
+ return
236
+ }
237
+ os .Stdout .WriteString (s )
238
+ }
239
+
229
240
func newResponseConsumer (cso * bedrockruntime.ConverseStreamOutput ) * responseConsumer {
230
241
return & responseConsumer {cso : cso }
231
242
}
@@ -283,10 +294,7 @@ func (r *responseConsumer) Chunks() iter.Seq[chunk] {
283
294
}
284
295
285
296
func readPrompt (args runArgs ) (string , error ) {
286
- var stdinIsTerminal bool
287
- if st , err := os .Stdin .Stat (); err == nil {
288
- stdinIsTerminal = st .Mode ()& os .ModeCharDevice != 0
289
- }
297
+ stdinIsTerminal := term .IsTerminal (int (os .Stdin .Fd ()))
290
298
var pb strings.Builder
291
299
var stdinData []byte
292
300
var err error
0 commit comments