Fix chat interface - restore continuous conversation flow

🎯 Major improvements to MissionControl component:
- Always keep input field visible and functional after AI responses
- Auto-clear input after submitting questions for better UX
- Add dynamic visual indicators (first question vs follow-up)
- Improve response layout with clear separation and hints
- Enable proper chat-like experience for continuous learning

🌟 Additional enhancements:
- Better language-specific messaging throughout interface
- Clearer visual hierarchy between input and response areas
- Intuitive flow that guides users to ask follow-up questions
- Maintains responsive design and accessibility

🔧 Technical changes:
- Enhanced MissionControl state management
- Improved component layout and styling
- Better TypeScript integration across components
- Updated tsconfig for stricter type checking
This commit is contained in:
rwiegand
2025-07-14 12:39:05 +02:00
parent b31492a354
commit f893530471
1798 changed files with 25329 additions and 92638 deletions

View File

@@ -1,8 +1,12 @@
"use strict";
var _AbstractChatCompletionRunner_instances, _AbstractChatCompletionRunner_getFinalContent, _AbstractChatCompletionRunner_getFinalMessage, _AbstractChatCompletionRunner_getFinalFunctionToolCall, _AbstractChatCompletionRunner_getFinalFunctionToolCallResult, _AbstractChatCompletionRunner_calculateTotalUsage, _AbstractChatCompletionRunner_validateParams, _AbstractChatCompletionRunner_stringifyFunctionCallResult;
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _AbstractChatCompletionRunner_instances, _AbstractChatCompletionRunner_getFinalContent, _AbstractChatCompletionRunner_getFinalMessage, _AbstractChatCompletionRunner_getFinalFunctionCall, _AbstractChatCompletionRunner_getFinalFunctionCallResult, _AbstractChatCompletionRunner_calculateTotalUsage, _AbstractChatCompletionRunner_validateParams, _AbstractChatCompletionRunner_stringifyFunctionCallResult;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractChatCompletionRunner = void 0;
const tslib_1 = require("../internal/tslib.js");
const error_1 = require("../error.js");
const RunnableFunction_1 = require("./RunnableFunction.js");
const chatCompletionUtils_1 = require("./chatCompletionUtils.js");
@@ -30,14 +34,17 @@ class AbstractChatCompletionRunner extends EventStream_1.EventStream {
this.messages.push(message);
if (emit) {
this._emit('message', message);
if ((0, chatCompletionUtils_1.isToolMessage)(message) && message.content) {
if (((0, chatCompletionUtils_1.isFunctionMessage)(message) || (0, chatCompletionUtils_1.isToolMessage)(message)) && message.content) {
// Note, this assumes that {role: 'tool', content: …} is always the result of a call of tool of type=function.
this._emit('functionToolCallResult', message.content);
this._emit('functionCallResult', message.content);
}
else if ((0, chatCompletionUtils_1.isAssistantMessage)(message) && message.function_call) {
this._emit('functionCall', message.function_call);
}
else if ((0, chatCompletionUtils_1.isAssistantMessage)(message) && message.tool_calls) {
for (const tool_call of message.tool_calls) {
if (tool_call.type === 'function') {
this._emit('functionToolCall', tool_call.function);
this._emit('functionCall', tool_call.function);
}
}
}
@@ -60,7 +67,7 @@ class AbstractChatCompletionRunner extends EventStream_1.EventStream {
*/
async finalContent() {
await this.done();
return tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalContent).call(this);
return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalContent).call(this);
}
/**
* @returns a promise that resolves with the the final assistant ChatCompletionMessage response,
@@ -68,23 +75,23 @@ class AbstractChatCompletionRunner extends EventStream_1.EventStream {
*/
async finalMessage() {
await this.done();
return tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this);
return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this);
}
/**
* @returns a promise that resolves with the content of the final FunctionCall, or rejects
* if an error occurred or the stream ended prematurely without producing a ChatCompletionMessage.
*/
async finalFunctionToolCall() {
async finalFunctionCall() {
await this.done();
return tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionToolCall).call(this);
return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionCall).call(this);
}
async finalFunctionToolCallResult() {
async finalFunctionCallResult() {
await this.done();
return tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionToolCallResult).call(this);
return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionCallResult).call(this);
}
async totalUsage() {
await this.done();
return tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_calculateTotalUsage).call(this);
return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_calculateTotalUsage).call(this);
}
allChatCompletions() {
return [...this._chatCompletions];
@@ -93,20 +100,20 @@ class AbstractChatCompletionRunner extends EventStream_1.EventStream {
const completion = this._chatCompletions[this._chatCompletions.length - 1];
if (completion)
this._emit('finalChatCompletion', completion);
const finalMessage = tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this);
const finalMessage = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this);
if (finalMessage)
this._emit('finalMessage', finalMessage);
const finalContent = tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalContent).call(this);
const finalContent = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalContent).call(this);
if (finalContent)
this._emit('finalContent', finalContent);
const finalFunctionCall = tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionToolCall).call(this);
const finalFunctionCall = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionCall).call(this);
if (finalFunctionCall)
this._emit('finalFunctionToolCall', finalFunctionCall);
const finalFunctionCallResult = tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionToolCallResult).call(this);
this._emit('finalFunctionCall', finalFunctionCall);
const finalFunctionCallResult = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalFunctionCallResult).call(this);
if (finalFunctionCallResult != null)
this._emit('finalFunctionToolCallResult', finalFunctionCallResult);
this._emit('finalFunctionCallResult', finalFunctionCallResult);
if (this._chatCompletions.some((c) => c.usage)) {
this._emit('totalUsage', tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_calculateTotalUsage).call(this));
this._emit('totalUsage', __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_calculateTotalUsage).call(this));
}
}
async _createChatCompletion(client, params, options) {
@@ -116,7 +123,7 @@ class AbstractChatCompletionRunner extends EventStream_1.EventStream {
this.controller.abort();
signal.addEventListener('abort', () => this.controller.abort());
}
tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_validateParams).call(this, params);
__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_validateParams).call(this, params);
const chatCompletion = await client.chat.completions.create({ ...params, stream: false }, { ...options, signal: this.controller.signal });
this._connected();
return this._addChatCompletion((0, parser_1.parseChatCompletion)(chatCompletion, params));
@@ -127,6 +134,70 @@ class AbstractChatCompletionRunner extends EventStream_1.EventStream {
}
return await this._createChatCompletion(client, params, options);
}
async _runFunctions(client, params, options) {
const role = 'function';
const { function_call = 'auto', stream, ...restParams } = params;
const singleFunctionToCall = typeof function_call !== 'string' && function_call?.name;
const { maxChatCompletions = DEFAULT_MAX_CHAT_COMPLETIONS } = options || {};
const functionsByName = {};
for (const f of params.functions) {
functionsByName[f.name || f.function.name] = f;
}
const functions = params.functions.map((f) => ({
name: f.name || f.function.name,
parameters: f.parameters,
description: f.description,
}));
for (const message of params.messages) {
this._addMessage(message, false);
}
for (let i = 0; i < maxChatCompletions; ++i) {
const chatCompletion = await this._createChatCompletion(client, {
...restParams,
function_call,
functions,
messages: [...this.messages],
}, options);
const message = chatCompletion.choices[0]?.message;
if (!message) {
throw new error_1.OpenAIError(`missing message in ChatCompletion response`);
}
if (!message.function_call)
return;
const { name, arguments: args } = message.function_call;
const fn = functionsByName[name];
if (!fn) {
const content = `Invalid function_call: ${JSON.stringify(name)}. Available options are: ${functions
.map((f) => JSON.stringify(f.name))
.join(', ')}. Please try again`;
this._addMessage({ role, name, content });
continue;
}
else if (singleFunctionToCall && singleFunctionToCall !== name) {
const content = `Invalid function_call: ${JSON.stringify(name)}. ${JSON.stringify(singleFunctionToCall)} requested. Please try again`;
this._addMessage({ role, name, content });
continue;
}
let parsed;
try {
parsed = (0, RunnableFunction_1.isRunnableFunctionWithParse)(fn) ? await fn.parse(args) : args;
}
catch (error) {
this._addMessage({
role,
name,
content: error instanceof Error ? error.message : String(error),
});
continue;
}
// @ts-expect-error it can't rule out `never` type.
const rawContent = await fn.function(parsed, this);
const content = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_stringifyFunctionCallResult).call(this, rawContent);
this._addMessage({ role, name, content });
if (singleFunctionToCall)
return;
}
}
async _runTools(client, params, options) {
const role = 'tool';
const { tool_choice = 'auto', stream, ...restParams } = params;
@@ -217,7 +288,7 @@ class AbstractChatCompletionRunner extends EventStream_1.EventStream {
}
// @ts-expect-error it can't rule out `never` type.
const rawContent = await fn.function(parsed, this);
const content = tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_stringifyFunctionCallResult).call(this, rawContent);
const content = __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_stringifyFunctionCallResult).call(this, rawContent);
this._addMessage({ role, tool_call_id, content });
if (singleFunctionToCall) {
return;
@@ -229,33 +300,43 @@ class AbstractChatCompletionRunner extends EventStream_1.EventStream {
}
exports.AbstractChatCompletionRunner = AbstractChatCompletionRunner;
_AbstractChatCompletionRunner_instances = new WeakSet(), _AbstractChatCompletionRunner_getFinalContent = function _AbstractChatCompletionRunner_getFinalContent() {
return tslib_1.__classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this).content ?? null;
return __classPrivateFieldGet(this, _AbstractChatCompletionRunner_instances, "m", _AbstractChatCompletionRunner_getFinalMessage).call(this).content ?? null;
}, _AbstractChatCompletionRunner_getFinalMessage = function _AbstractChatCompletionRunner_getFinalMessage() {
let i = this.messages.length;
while (i-- > 0) {
const message = this.messages[i];
if ((0, chatCompletionUtils_1.isAssistantMessage)(message)) {
const { function_call, ...rest } = message;
// TODO: support audio here
const ret = {
...message,
...rest,
content: message.content ?? null,
refusal: message.refusal ?? null,
};
if (function_call) {
ret.function_call = function_call;
}
return ret;
}
}
throw new error_1.OpenAIError('stream ended without producing a ChatCompletionMessage with role=assistant');
}, _AbstractChatCompletionRunner_getFinalFunctionToolCall = function _AbstractChatCompletionRunner_getFinalFunctionToolCall() {
}, _AbstractChatCompletionRunner_getFinalFunctionCall = function _AbstractChatCompletionRunner_getFinalFunctionCall() {
for (let i = this.messages.length - 1; i >= 0; i--) {
const message = this.messages[i];
if ((0, chatCompletionUtils_1.isAssistantMessage)(message) && message?.function_call) {
return message.function_call;
}
if ((0, chatCompletionUtils_1.isAssistantMessage)(message) && message?.tool_calls?.length) {
return message.tool_calls.at(-1)?.function;
}
}
return;
}, _AbstractChatCompletionRunner_getFinalFunctionToolCallResult = function _AbstractChatCompletionRunner_getFinalFunctionToolCallResult() {
}, _AbstractChatCompletionRunner_getFinalFunctionCallResult = function _AbstractChatCompletionRunner_getFinalFunctionCallResult() {
for (let i = this.messages.length - 1; i >= 0; i--) {
const message = this.messages[i];
if ((0, chatCompletionUtils_1.isFunctionMessage)(message) && message.content != null) {
return message.content;
}
if ((0, chatCompletionUtils_1.isToolMessage)(message) &&
message.content != null &&
typeof message.content === 'string' &&