Skip to content

Webui: Enable communication with parent html (if webui is in iframe): #11940

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Feb 18, 2025

Conversation

igardev
Copy link
Contributor

@igardev igardev commented Feb 18, 2025

  • Listens for "setText" command from parent with "text" and "context" fields. "text" is set in inputMsg, "context" is used as hidden context on the following requests to llama.cpp server
  • On pressing an Escape button sends command "escapePressed" to the parent

Example handling from the parent html side:

  • Send command "setText" from parent html to webui in iframe:
    const iframe = document.getElementById('askAiIframe');
    if (iframe) {
    iframe.contentWindow.postMessage({ command: 'setText', text: text, context: context }, '*');
    }

  • Listen for Escape key from webui on parent html:
    // Listen for escape key event from iframe
    if (command === 'escapePressed') {
    // Process case when escape is pressed in webui
    };

Make sure to read the contributing guidelines before submitting a PR

I need this change for llama.vscode extension (code completion). The goal is to show inside VS Code a window with Webui and send from VS Code the project context to Webui (and also set the selected text, if any, in inputMsg).

image

- Listens for "setText" command from parent with "text" and "context" fields. "text" is set in inputMsg, "context" is used as hidden context on the following requests to the llama.cpp server
- On pressing na Escape button sends command "escapePressed" to the parent

Example handling from the parent html side:
- Send command "setText" from parent html to webui in iframe:
const iframe = document.getElementById('askAiIframe');
if (iframe) {
	iframe.contentWindow.postMessage({ command: 'setText', text: text, context: context }, '*');
}

- Listen for Escape key from webui on parent html:
// Listen for escape key event in the iframe
window.addEventListener('keydown', (event) => {
	if (event.key === 'Escape') {
		// Process case when Escape is pressed inside webui
	}
});
@@ -21,6 +21,7 @@ const dispatchConversationChange = (convId: string) => {
const db = new Dexie('LlamacppWebui') as Dexie & {
conversations: Table<Conversation>;
messages: Table<Message>;
extraContext: string;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be stored in app.context.tsx instead of here. The DB class is meant to store permanent data.

Also, you only define the type here, not the initial value. extraContext can de undefined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extraContext is in some sense permanent as it is reused in each request to llama.cpp server. However, you are right - it is better to move it in app.context.

async setExtraContext(extraContext: string): Promise<void> {
db.extraContext = extraContext
},
async getExtraContext(): Promise<string> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either define a default value, or explicitly tell that it is undefine-able:

Suggested change
async getExtraContext(): Promise<string> {
async getExtraContext(): Promise<string | undefined> {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As extraContext will be moved in app.context, this function will be removed.

let extraContext:string = await StorageUtils.getExtraContext()
if (extraContext && extraContext != ""){
// insert extra context just after the systemMessage
messages.splice(config.systemMessage.length === 0 ? 0 : 1, 0, { role: 'user', content:extraContext } as APIMessage)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may not be a good idea. Some models ignore system prompt. It should be injected into user message instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this puts the extra context message as a user message just before the other user messages. Is there something wrong?

@ngxson
Copy link
Collaborator

ngxson commented Feb 18, 2025

Btw, I'm having a plan to introduce a set of extraElements into the Message object. This will allow storing text, file, thought process, etc into the message. I think that would fit better into what you're trying to do here, as you can just put the extraContent as file content.

@igardev
Copy link
Contributor Author

igardev commented Feb 18, 2025

Message

OK, if it is not a problem, let's introduce this change now and when you update the Message class we could change it. It is not a big update.

@ngxson
Copy link
Collaborator

ngxson commented Feb 18, 2025

I'll push the new Message object to this PR, I'm working on it. This can also allow you to specify the file name for the input content.

@ngxson
Copy link
Collaborator

ngxson commented Feb 18, 2025

@igardev Here is how it looks now, can you test it please?

window.postMessage({ command: 'setText', text: 'Spot the syntax error', context: 'def test()\n  return 123' }, '*');
image

Copy link
Contributor Author

@igardev igardev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the improvements!
One remark - the extraContext could be huge and changes slowly. If we send the complete extraContext with every message the conversation size will increase quickly.
Let's merge the current implementation and continue thinking for a better one.

for (const extra of msg.extra ?? []) {
if (extra.type === 'textFile') {
// TODO: allow user to customize this via Settings
newContent += `\n===\nExtra file: ${extra.name}\n${extra.content}\n\n===\n`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extraContext is not one file, but a combination of many:
image

"Extra file: " could confuse the model. I would suggest to remove it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 4bbd48d

@ngxson
Copy link
Collaborator

ngxson commented Feb 18, 2025

One remark - the extraContext could be huge and changes slowly. If we send the complete extraContext with every message the conversation size will increase quickly.

extraContext is only attached to the first message of the conversation and will stay there. It won't be added to the second message sent from user. I imagine this should be the same with other platforms like chatgpt / GH copilot / etc

If we completely remove the extra from the conversation, it will make a bad UX because user may ask follow up questions about the same code.

@ngxson ngxson merged commit b58934c into ggml-org:master Feb 18, 2025
6 checks passed
orca-zhang pushed a commit to orca-zhang/llama.cpp that referenced this pull request Feb 26, 2025
…n iframe) (ggml-org#11940)

* Webui: Enable communication with parent html (if webui is in iframe):
- Listens for "setText" command from parent with "text" and "context" fields. "text" is set in inputMsg, "context" is used as hidden context on the following requests to the llama.cpp server
- On pressing na Escape button sends command "escapePressed" to the parent

Example handling from the parent html side:
- Send command "setText" from parent html to webui in iframe:
const iframe = document.getElementById('askAiIframe');
if (iframe) {
	iframe.contentWindow.postMessage({ command: 'setText', text: text, context: context }, '*');
}

- Listen for Escape key from webui on parent html:
// Listen for escape key event in the iframe
window.addEventListener('keydown', (event) => {
	if (event.key === 'Escape') {
		// Process case when Escape is pressed inside webui
	}
});

* Move the extraContext from storage to app.context.

* Fix formatting.

* add Message.extra

* format + build

* MessageExtraContext

* build

* fix display

* rm console.log

---------

Co-authored-by: igardev <[email protected]>
Co-authored-by: Xuan Son Nguyen <[email protected]>
arthw pushed a commit to arthw/llama.cpp that referenced this pull request Feb 26, 2025
…n iframe) (ggml-org#11940)

* Webui: Enable communication with parent html (if webui is in iframe):
- Listens for "setText" command from parent with "text" and "context" fields. "text" is set in inputMsg, "context" is used as hidden context on the following requests to the llama.cpp server
- On pressing na Escape button sends command "escapePressed" to the parent

Example handling from the parent html side:
- Send command "setText" from parent html to webui in iframe:
const iframe = document.getElementById('askAiIframe');
if (iframe) {
	iframe.contentWindow.postMessage({ command: 'setText', text: text, context: context }, '*');
}

- Listen for Escape key from webui on parent html:
// Listen for escape key event in the iframe
window.addEventListener('keydown', (event) => {
	if (event.key === 'Escape') {
		// Process case when Escape is pressed inside webui
	}
});

* Move the extraContext from storage to app.context.

* Fix formatting.

* add Message.extra

* format + build

* MessageExtraContext

* build

* fix display

* rm console.log

---------

Co-authored-by: igardev <[email protected]>
Co-authored-by: Xuan Son Nguyen <[email protected]>
mglambda pushed a commit to mglambda/llama.cpp that referenced this pull request Mar 8, 2025
…n iframe) (ggml-org#11940)

* Webui: Enable communication with parent html (if webui is in iframe):
- Listens for "setText" command from parent with "text" and "context" fields. "text" is set in inputMsg, "context" is used as hidden context on the following requests to the llama.cpp server
- On pressing na Escape button sends command "escapePressed" to the parent

Example handling from the parent html side:
- Send command "setText" from parent html to webui in iframe:
const iframe = document.getElementById('askAiIframe');
if (iframe) {
	iframe.contentWindow.postMessage({ command: 'setText', text: text, context: context }, '*');
}

- Listen for Escape key from webui on parent html:
// Listen for escape key event in the iframe
window.addEventListener('keydown', (event) => {
	if (event.key === 'Escape') {
		// Process case when Escape is pressed inside webui
	}
});

* Move the extraContext from storage to app.context.

* Fix formatting.

* add Message.extra

* format + build

* MessageExtraContext

* build

* fix display

* rm console.log

---------

Co-authored-by: igardev <[email protected]>
Co-authored-by: Xuan Son Nguyen <[email protected]>
mostlyuseful pushed a commit to mostlyuseful/llama.cpp that referenced this pull request May 12, 2025
…n iframe) (ggml-org#11940)

* Webui: Enable communication with parent html (if webui is in iframe):
- Listens for "setText" command from parent with "text" and "context" fields. "text" is set in inputMsg, "context" is used as hidden context on the following requests to the llama.cpp server
- On pressing na Escape button sends command "escapePressed" to the parent

Example handling from the parent html side:
- Send command "setText" from parent html to webui in iframe:
const iframe = document.getElementById('askAiIframe');
if (iframe) {
	iframe.contentWindow.postMessage({ command: 'setText', text: text, context: context }, '*');
}

- Listen for Escape key from webui on parent html:
// Listen for escape key event in the iframe
window.addEventListener('keydown', (event) => {
	if (event.key === 'Escape') {
		// Process case when Escape is pressed inside webui
	}
});

* Move the extraContext from storage to app.context.

* Fix formatting.

* add Message.extra

* format + build

* MessageExtraContext

* build

* fix display

* rm console.log

---------

Co-authored-by: igardev <[email protected]>
Co-authored-by: Xuan Son Nguyen <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants