Add documentation for using Milkdown with various frameworks
- Created a new document for using components in Milkdown. - Added a guide for using plugins in Milkdown, including toggling plugins programmatically and listing official plugins. - Introduced a recipe for integrating Milkdown with Angular, including installation steps and component creation. - Added a recipe for using Milkdown with Next.js, detailing installation and component setup. - Created a guide for integrating Milkdown with NuxtJS, including installation and component creation. - Added a comprehensive guide for using Milkdown with React, covering both Crepe and core Milkdown usage. - Introduced a recipe for SolidJS integration with Milkdown, including installation and component creation. - Added a guide for using Milkdown with Svelte, detailing installation and component setup. - Created a comprehensive guide for integrating Milkdown with Vue, covering both Crepe and core Milkdown usage. - Added a recipe for using Milkdown with Vue2, including installation and component creation.
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { createServiceIdentifier } from '../../../../../../util/common/services';
|
||||
import { APIChoice } from '../openai/openai';
|
||||
import { ResultType } from './ghostText';
|
||||
|
||||
export const ICompletionsCurrentGhostText = createServiceIdentifier<ICompletionsCurrentGhostText>('ICompletionsCurrentGhostText');
|
||||
export interface ICompletionsCurrentGhostText {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
readonly clientCompletionId: string | undefined;
|
||||
|
||||
currentRequestId: string | undefined;
|
||||
|
||||
setGhostText(prefix: string, suffix: string, choices: APIChoice[], resultType: ResultType): void;
|
||||
getCompletionsForUserTyping(prefix: string, suffix: string): APIChoice[] | undefined;
|
||||
hasAcceptedCurrentCompletion(prefix: string, suffix: string): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the internal concept of the currently shown completion, as inferred by
|
||||
* the output of getGhostText. Used to check if a subsequent call to
|
||||
* getGhostText is typing-as-suggested.
|
||||
*/
|
||||
export class CurrentGhostText implements ICompletionsCurrentGhostText {
|
||||
declare _serviceBrand: undefined;
|
||||
/** The document prefix at the start of the typing-as-suggested flow. This
|
||||
* does not use the prompt prefix since the ellision means that prefix is a
|
||||
* sliding window over long documents. */
|
||||
private prefix?: string;
|
||||
|
||||
/** The prompt suffix at the start of the typing-as-suggested flow. */
|
||||
private suffix?: string;
|
||||
|
||||
/** The original APIChoice array created at the start of the
|
||||
* typing-as-suggested flow. The first element in the array should be the
|
||||
* completion shown to the user. */
|
||||
private choices: APIChoice[] = [];
|
||||
|
||||
/** The currently shown completion id. */
|
||||
get clientCompletionId(): string | undefined {
|
||||
return this.choices[0]?.clientCompletionId;
|
||||
}
|
||||
|
||||
/** The most recent inline completion request id, excluding speculative requests. */
|
||||
currentRequestId: string | undefined;
|
||||
|
||||
/** Updates the current ghost text if it was not produced via
|
||||
* TypingAsSuggested. Should only be called from the end of getGhostText. */
|
||||
setGhostText(prefix: string, suffix: string, choices: APIChoice[], resultType: ResultType) {
|
||||
if (resultType === ResultType.TypingAsSuggested) { return; }
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.choices = choices;
|
||||
}
|
||||
|
||||
/** Returns the current choices if the request context matches. */
|
||||
getCompletionsForUserTyping(prefix: string, suffix: string): APIChoice[] | undefined {
|
||||
const remainingPrefix = this.getRemainingPrefix(prefix, suffix);
|
||||
if (remainingPrefix === undefined) { return; }
|
||||
// If the first choice text does not match return empty to fall through
|
||||
// to either the cache or network.
|
||||
if (!startsWithAndExceeds(this.choices[0].completionText, remainingPrefix)) { return; }
|
||||
return adjustChoicesStart(this.choices, remainingPrefix);
|
||||
}
|
||||
|
||||
/** Returns whether the current completion is fully completed, and covers a full line. */
|
||||
hasAcceptedCurrentCompletion(prefix: string, suffix: string): boolean {
|
||||
const remainingPrefix = this.getRemainingPrefix(prefix, suffix);
|
||||
if (remainingPrefix === undefined) { return false; }
|
||||
|
||||
// Check if the completion text matches exactly
|
||||
const exactMatch = remainingPrefix === this.choices?.[0].completionText;
|
||||
|
||||
// Check finishReason - return false if it indicates that the server cut off a part of it (thus it might not complete a full line), due to RAI or snippy
|
||||
const finishReason = this.choices?.[0].finishReason;
|
||||
return exactMatch && finishReason === 'stop';
|
||||
}
|
||||
|
||||
/** If the given document prefix and prompt suffix match the current
|
||||
* completion returns the remaining prefix of the document after the stored
|
||||
* prefix. Returns undefined if the completion does not match. */
|
||||
private getRemainingPrefix(prefix: string, suffix: string): string | undefined {
|
||||
// Check that there is a current completion.
|
||||
if (this.prefix === undefined || this.suffix === undefined || this.choices.length === 0) { return; }
|
||||
// Check that the prompt suffixes are an exact match.
|
||||
if (this.suffix !== suffix) { return; }
|
||||
// Check that the document prefix is a prefix of the new prefix.
|
||||
// This doesn't use the prompt prefix since the ellision means that
|
||||
// subsequent prefixes will not be a prefix of earlier ones.
|
||||
if (!prefix.startsWith(this.prefix)) { return; }
|
||||
// Return the remaining new document prefix after the prefix stored for
|
||||
// the current completion.
|
||||
return prefix.substring(this.prefix.length);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns choices adjusted to remove the remainingPrefix from the start of the
|
||||
* completionText if it matches. */
|
||||
function adjustChoicesStart(choices: APIChoice[], remainingPrefix: string): APIChoice[] {
|
||||
return choices
|
||||
.filter(choice => startsWithAndExceeds(choice.completionText, remainingPrefix))
|
||||
.map(choice => ({
|
||||
...choice,
|
||||
completionText: choice.completionText.substring(remainingPrefix.length),
|
||||
}));
|
||||
}
|
||||
|
||||
/** Returns true if `prefix` is a prefix of `text` and `text` is longer. */
|
||||
function startsWithAndExceeds(text: string, prefix: string) {
|
||||
return text.startsWith(prefix) && text.length > prefix.length;
|
||||
}
|
||||
Reference in New Issue
Block a user