diff --git a/cli/src/commands/run/app/_strategies/streaming-structured.ts b/cli/src/commands/run/app/_strategies/streaming-structured.ts index 2089762d8d..b85db1d808 100644 --- a/cli/src/commands/run/app/_strategies/streaming-structured.ts +++ b/cli/src/commands/run/app/_strategies/streaming-structured.ts @@ -1,6 +1,7 @@ import type { SseEvent } from '../../../../http/sse.js' import type { RunContext, RunStrategy } from './index.js' import { buildRunBody } from '../../../../api/app-run.js' +import { colorEnabled, colorScheme } from '../../../../io/color.js' import { startSpinner } from '../../../../io/spinner.js' import { extractThinkBlocks, stripThinkBlocks } from '../../../../io/think-filter.js' import { chatConversationHint, newAppRunObject, RUN_MODES } from '../handlers.js' @@ -89,7 +90,8 @@ export class StreamingStructuredStrategy implements RunStrategy { const respMode = typeof processedResp.mode === 'string' && processedResp.mode !== '' ? processedResp.mode : mode deps.io.out.write(printFlags.toPrinter(format).print(newAppRunObject(respMode, processedResp))) if (isText && CHAT_MODES.has(respMode)) { - const hint = chatConversationHint(processedResp) + const cs = colorScheme(colorEnabled(deps.io.isErrTTY)) + const hint = chatConversationHint(processedResp, cs) if (hint !== undefined) deps.io.err.write(hint) } diff --git a/cli/src/commands/run/app/_strategies/streaming-text.ts b/cli/src/commands/run/app/_strategies/streaming-text.ts index 3a23e14791..6a5405a918 100644 --- a/cli/src/commands/run/app/_strategies/streaming-text.ts +++ b/cli/src/commands/run/app/_strategies/streaming-text.ts @@ -26,7 +26,7 @@ export class StreamingTextStrategy implements RunStrategy { try { const events = await ctx.runClient.runStream(opts.appId, body, { signal: ctrl.signal }) - const sp = printFlags.toStreamPrinter(mode, ctx.think) + const sp = printFlags.toStreamPrinter(mode, ctx.think, deps.io.isErrTTY) const dec = new TextDecoder() for await (const ev of events) { if (ev.name === 'ping') diff --git a/cli/src/commands/run/app/file-flags.test.ts b/cli/src/commands/run/app/file-flags.test.ts index 8f0216a6f0..87babdedec 100644 --- a/cli/src/commands/run/app/file-flags.test.ts +++ b/cli/src/commands/run/app/file-flags.test.ts @@ -62,8 +62,8 @@ describe('difyFileType', () => { expect(difyFileType('notes.md')).toBe('document') }) - it('returns custom for unknown extension', () => { - expect(difyFileType('data.xyz')).toBe('custom') + it('returns document for unknown extension', () => { + expect(difyFileType('data.xyz')).toBe('document') }) it('returns custom for no extension', () => { diff --git a/cli/src/commands/run/app/handlers.ts b/cli/src/commands/run/app/handlers.ts index 2d040246b4..2cc11b026c 100644 --- a/cli/src/commands/run/app/handlers.ts +++ b/cli/src/commands/run/app/handlers.ts @@ -1,3 +1,4 @@ +import type { ColorScheme } from '../../../io/color.js' import type { TextHandler } from '../../../printers/format-text.js' export const RUN_MODES = { @@ -59,11 +60,11 @@ export const workflowTextHandler: TextHandler = { }, } -export function chatConversationHint(resp: Record): string | undefined { +export function chatConversationHint(resp: Record, cs: ColorScheme): string | undefined { const cid = pickString(resp, 'conversation_id') if (cid === undefined || cid === '') return undefined - return `hint: continue this conversation with --conversation ${cid}\n` + return `${cs.magenta('hint:')} continue this conversation with --conversation ${cs.cyan(cid)}\n` } function pickString(o: Record, key: string): string | undefined { diff --git a/cli/src/commands/run/app/print-flags.ts b/cli/src/commands/run/app/print-flags.ts index 8001bc6fc5..a90d7b8f8c 100644 --- a/cli/src/commands/run/app/print-flags.ts +++ b/cli/src/commands/run/app/print-flags.ts @@ -21,7 +21,7 @@ export class AppRunPrintFlags extends CompositePrintFlags { return [this.jsonYaml, this.text] } - toStreamPrinter(mode: string, think = false): StreamPrinter { - return streamPrinterFor(mode, think) + toStreamPrinter(mode: string, think = false, isTTY = false): StreamPrinter { + return streamPrinterFor(mode, think, isTTY) } } diff --git a/cli/src/commands/run/app/stream-handlers.ts b/cli/src/commands/run/app/stream-handlers.ts index 64d21ea3f2..a54dbfe54b 100644 --- a/cli/src/commands/run/app/stream-handlers.ts +++ b/cli/src/commands/run/app/stream-handlers.ts @@ -3,6 +3,7 @@ import type { StreamPrinter } from '../../../printers/stream-printer.js' import type { HitlPausePayload } from './sse-collector.js' import { newError } from '../../../errors/base.js' import { ErrorCode } from '../../../errors/codes.js' +import { colorEnabled, colorScheme } from '../../../io/color.js' import { ThinkChunkFilter } from '../../../io/think-filter.js' import { RUN_MODES } from './handlers.js' import { HitlPauseError } from './sse-collector.js' @@ -42,8 +43,10 @@ function handleCommonEvents(ev: SseEvent): boolean { class ChatStreamPrinter implements StreamPrinter { private convoId = '' private readonly filter: ThinkChunkFilter - constructor(think: boolean) { + private readonly isTTY: boolean + constructor(think: boolean, isTTY = false) { this.filter = new ThinkChunkFilter(think) + this.isTTY = isTTY } onEvent(out: NodeJS.WritableStream, errOut: NodeJS.WritableStream, ev: SseEvent): void { @@ -72,8 +75,10 @@ class ChatStreamPrinter implements StreamPrinter { onEnd(out: NodeJS.WritableStream, errOut: NodeJS.WritableStream): void { this.filter.flush(out, errOut) out.write('\n') - if (this.convoId !== '') - errOut.write(`hint: continue this conversation with --conversation ${this.convoId}\n`) + if (this.convoId !== '') { + const cs = colorScheme(colorEnabled(this.isTTY)) + errOut.write(`${cs.magenta('hint:')} continue this conversation with --conversation ${cs.cyan(this.convoId)}\n`) + } } } @@ -139,17 +144,17 @@ class WorkflowStreamPrinter implements StreamPrinter { } } -const FACTORIES: Record StreamPrinter> = { - [RUN_MODES.Chat]: think => new ChatStreamPrinter(think), - [RUN_MODES.AdvancedChat]: think => new ChatStreamPrinter(think), - [RUN_MODES.AgentChat]: think => new ChatStreamPrinter(think), - [RUN_MODES.Completion]: think => new CompletionStreamPrinter(think), - [RUN_MODES.Workflow]: _think => new WorkflowStreamPrinter(), +const FACTORIES: Record StreamPrinter> = { + [RUN_MODES.Chat]: (think, isTTY) => new ChatStreamPrinter(think, isTTY), + [RUN_MODES.AdvancedChat]: (think, isTTY) => new ChatStreamPrinter(think, isTTY), + [RUN_MODES.AgentChat]: (think, isTTY) => new ChatStreamPrinter(think, isTTY), + [RUN_MODES.Completion]: (think, _isTTY) => new CompletionStreamPrinter(think), + [RUN_MODES.Workflow]: (_think, _isTTY) => new WorkflowStreamPrinter(), } -export function streamPrinterFor(mode: string, think = false): StreamPrinter { +export function streamPrinterFor(mode: string, think = false, isTTY = false): StreamPrinter { const f = FACTORIES[mode] if (f === undefined) throw newError(ErrorCode.Unknown, `unsupported streaming mode "${mode}"`) - return f(think) + return f(think, isTTY) }