Add multi-line input, /model and /provider commands

ober

763ee587076be667f2fd24887c0b43b3af8ab2cf

diff --git a/lib/jcode/ui/cli.sls b/lib/jcode/ui/cli.sls
index f9af97b..b90195a 100644
--- a/lib/jcode/ui/cli.sls
+++ b/lib/jcode/ui/cli.sls
@@ -103,7 +103,7 @@
   (def (repl-loop session-id)
        (display (make-prompt))
        (flush-output-port (current-output-port))
-       (let ([input (get-line (current-input-port))])
+       (let ([input (read-multiline)])
          (cond
            [(eof-object? input) (newline) (printf "Goodbye!~n")]
            [(equal? input "") (repl-loop session-id)]
@@ -114,19 +114,75 @@
            [else
             (handle-user-input input session-id)
             (repl-loop session-id)])))
+  (def (read-multiline)
+       (let ([line (get-line (current-input-port))])
+         (if (eof-object? line)
+             line
+             (let loop ([line line] [acc '()])
+               (if (and (> (string-length line) 0)
+                        (char=?
+                          (string-ref line (- (string-length line) 1))
+                          #\\))
+                   (begin
+                     (display "  ... ")
+                     (flush-output-port (current-output-port))
+                     (let ([next (get-line (current-input-port))])
+                       (if (eof-object? next)
+                           (string-join
+                             (reverse
+                               (cons
+                                 (substring
+                                   line
+                                   0
+                                   (- (string-length line) 1))
+                                 acc))
+                             "\n")
+                           (loop
+                             next
+                             (cons
+                               (string-append
+                                 (substring
+                                   line
+                                   0
+                                   (- (string-length line) 1))
+                                 "\n")
+                               acc)))))
+                   (string-join (reverse (cons line acc)) ""))))))
   (def (handle-command input session-id)
        (let ([cmd (string-trim
                     (substring input 1 (string-length input)))])
          (cond
            [(equal? cmd "help")
             (display
-              "\nCommands:\n  /help       Show this help\n  /model      Show current model and provider\n  /tools      List available tools\n  /clear      Start a new session\n  /sessions   List saved sessions\n  /compact    Show message count\n  /quit       Exit\n\n")]
+              "\nCommands:\n  /help              Show this help\n  /model [name]      Show or set model\n  /provider [name]   Show or set provider\n  /tools             List available tools\n  /clear             Start a new session\n  /sessions          List saved sessions\n  /compact           Show message count\n  /quit              Exit\n\nMulti-line: end a line with \\ to continue on the next line.\n\n")]
            [(equal? cmd "model")
-            (printf "Provider: ~a~n" (config-provider))
-            (printf "Model:    ~a~n" (config-model))
+            (printf
+              "Provider: ~a~n"
+              (or (current-provider-override) (config-provider)))
+            (printf
+              "Model:    ~a~n"
+              (or (current-model-override) (config-model)))
             (printf
               "API Key:  ~a~n"
               (if (config-api-key) "configured" "not set"))]
+           [(string-prefix? "model " cmd)
+            (let ([new-model (string-trim
+                               (substring cmd 6 (string-length cmd)))])
+              (current-model-override new-model)
+              (printf "Model set to: ~a~n" new-model))]
+           [(equal? cmd "provider")
+            (printf
+              "Provider: ~a~n"
+              (or (current-provider-override) (config-provider)))]
+           [(string-prefix? "provider " cmd)
+            (let ([new-provider (string-trim
+                                  (substring cmd 9 (string-length cmd)))])
+              (current-provider-override new-provider)
+              (current-model-override (config-default-model new-provider))
+              (printf
+                "Provider set to: ~a (model: ~a)~n"
+                new-provider
+                (current-model-override)))]
            [(equal? cmd "tools")
             (printf
               "Available tools: ~a~n"
diff --git a/src/jcode/ui/cli.ss b/src/jcode/ui/cli.ss
index 3bd869c..3eebbfc 100644
--- a/src/jcode/ui/cli.ss
+++ b/src/jcode/ui/cli.ss
@@ -121,7 +121,7 @@ EXAMPLES:
 (def (repl-loop session-id)
   (display (make-prompt))
   (flush-output-port (current-output-port))
-  (let ((input (get-line (current-input-port))))
+  (let ((input (read-multiline)))
     (cond
       ((eof-object? input)
        (newline)
@@ -135,15 +135,42 @@ EXAMPLES:
        (handle-user-input input session-id)
        (repl-loop session-id)))))
 
+(def (read-multiline)
+  ;; Read input, continuing on lines ending with backslash
+  (let ((line (get-line (current-input-port))))
+    (if (eof-object? line) line
+      (let loop ((line line) (acc '()))
+        (if (and (> (string-length line) 0)
+                 (char=? (string-ref line (- (string-length line) 1)) #\\))
+          (begin
+            (display "  ... ")
+            (flush-output-port (current-output-port))
+            (let ((next (get-line (current-input-port))))
+              (if (eof-object? next)
+                (string-join (reverse (cons (substring line 0 (- (string-length line) 1)) acc)) "\n")
+                (loop next (cons (string-append (substring line 0 (- (string-length line) 1)) "\n") acc)))))
+          (string-join (reverse (cons line acc)) ""))))))
+
 (def (handle-command input session-id)
   (let ((cmd (string-trim (substring input 1 (string-length input)))))
     (cond
       ((equal? cmd "help")
-       (display "\nCommands:\n  /help       Show this help\n  /model      Show current model and provider\n  /tools      List available tools\n  /clear      Start a new session\n  /sessions   List saved sessions\n  /compact    Show message count\n  /quit       Exit\n\n"))
+       (display "\nCommands:\n  /help              Show this help\n  /model [name]      Show or set model\n  /provider [name]   Show or set provider\n  /tools             List available tools\n  /clear             Start a new session\n  /sessions          List saved sessions\n  /compact           Show message count\n  /quit              Exit\n\nMulti-line: end a line with \\ to continue on the next line.\n\n"))
       ((equal? cmd "model")
-       (printf "Provider: ~a~n" (config-provider))
-       (printf "Model:    ~a~n" (config-model))
+       (printf "Provider: ~a~n" (or (current-provider-override) (config-provider)))
+       (printf "Model:    ~a~n" (or (current-model-override) (config-model)))
        (printf "API Key:  ~a~n" (if (config-api-key) "configured" "not set")))
+      ((string-prefix? "model " cmd)
+       (let ((new-model (string-trim (substring cmd 6 (string-length cmd)))))
+         (current-model-override new-model)
+         (printf "Model set to: ~a~n" new-model)))
+      ((equal? cmd "provider")
+       (printf "Provider: ~a~n" (or (current-provider-override) (config-provider))))
+      ((string-prefix? "provider " cmd)
+       (let ((new-provider (string-trim (substring cmd 9 (string-length cmd)))))
+         (current-provider-override new-provider)
+         (current-model-override (config-default-model new-provider))
+         (printf "Provider set to: ~a (model: ~a)~n" new-provider (current-model-override))))
       ((equal? cmd "tools")
        (printf "Available tools: ~a~n" (string-join (list-tools) ", ")))
       ((equal? cmd "clear")