Skip to content
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

feat: Integrate SCANOSS #14628

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/browser-only/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@theia/ai-history": "1.56.0",
"@theia/ai-ollama": "1.56.0",
"@theia/ai-openai": "1.56.0",
"@theia/ai-scanoss": "1.56.0",
"@theia/api-samples": "1.56.0",
"@theia/bulk-edit": "1.56.0",
"@theia/callhierarchy": "1.56.0",
Expand Down Expand Up @@ -53,6 +54,7 @@
"@theia/preview": "1.56.0",
"@theia/process": "1.56.0",
"@theia/property-view": "1.56.0",
"@theia/scanoss": "1.56.0",
"@theia/scm": "1.56.0",
"@theia/scm-extra": "1.56.0",
"@theia/search-in-workspace": "1.56.0",
Expand Down
6 changes: 6 additions & 0 deletions examples/browser-only/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
{
"path": "../../packages/ai-openai"
},
{
"path": "../../packages/ai-scanoss"
},
{
"path": "../../packages/bulk-edit"
},
Expand Down Expand Up @@ -119,6 +122,9 @@
{
"path": "../../packages/property-view"
},
{
"path": "../../packages/scanoss"
},
{
"path": "../../packages/scm"
},
Expand Down
2 changes: 2 additions & 0 deletions examples/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@theia/ai-mcp": "1.56.0",
"@theia/ai-ollama": "1.56.0",
"@theia/ai-openai": "1.56.0",
"@theia/ai-scanoss": "1.56.0",
"@theia/ai-terminal": "1.56.0",
"@theia/ai-workspace-agent": "1.56.0",
"@theia/api-provider-sample": "1.56.0",
Expand Down Expand Up @@ -70,6 +71,7 @@
"@theia/process": "1.56.0",
"@theia/property-view": "1.56.0",
"@theia/remote": "1.56.0",
"@theia/scanoss": "1.56.0",
"@theia/scm": "1.56.0",
"@theia/scm-extra": "1.56.0",
"@theia/search-in-workspace": "1.56.0",
Expand Down
6 changes: 6 additions & 0 deletions examples/browser/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
{
"path": "../../packages/ai-openai"
},
{
"path": "../../packages/ai-scanoss"
},
{
"path": "../../packages/ai-terminal"
},
Expand Down Expand Up @@ -146,6 +149,9 @@
{
"path": "../../packages/remote"
},
{
"path": "../../packages/scanoss"
},
{
"path": "../../packages/scm"
},
Expand Down
2 changes: 2 additions & 0 deletions examples/electron/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@theia/ai-llamafile": "1.56.0",
"@theia/ai-ollama": "1.56.0",
"@theia/ai-openai": "1.56.0",
"@theia/ai-scanoss": "1.56.0",
"@theia/ai-terminal": "1.56.0",
"@theia/ai-workspace-agent": "1.56.0",
"@theia/api-provider-sample": "1.56.0",
Expand Down Expand Up @@ -72,6 +73,7 @@
"@theia/process": "1.56.0",
"@theia/property-view": "1.56.0",
"@theia/remote": "1.56.0",
"@theia/scanoss": "1.56.0",
"@theia/scm": "1.56.0",
"@theia/scm-extra": "1.56.0",
"@theia/search-in-workspace": "1.56.0",
Expand Down
6 changes: 6 additions & 0 deletions examples/electron/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
{
"path": "../../packages/ai-openai"
},
{
"path": "../../packages/ai-scanoss"
},
{
"path": "../../packages/ai-terminal"
},
Expand Down Expand Up @@ -140,6 +143,9 @@
{
"path": "../../packages/remote"
},
{
"path": "../../packages/scanoss"
},
{
"path": "../../packages/scm"
},
Expand Down
27 changes: 23 additions & 4 deletions packages/ai-chat-ui/src/browser/ai-chat-ui-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,27 @@ import { bindViewContribution, FrontendApplicationContribution, WidgetFactory }
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
import { EditorManager } from '@theia/editor/lib/browser';
import '../../src/browser/style/index.css';
import { AIChatContribution } from './ai-chat-ui-contribution';
import { AIChatInputWidget } from './chat-input-widget';
import { ChatNodeToolbarActionContribution } from './chat-node-toolbar-action-contribution';
import { ChatResponsePartRenderer } from './chat-response-part-renderer';
import { CodePartRenderer, CommandPartRenderer, ErrorPartRenderer, HorizontalLayoutPartRenderer, MarkdownPartRenderer, ToolCallPartRenderer } from './chat-response-renderer';
import {
AIEditorManager, AIEditorSelectionResolver,
GitHubSelectionResolver, TextFragmentSelectionResolver, TypeDocSymbolSelectionResolver
CodePartRenderer,
CodePartRendererAction,
CommandPartRenderer,
CopyToClipboardButtonAction,
ErrorPartRenderer,
HorizontalLayoutPartRenderer,
InsertCodeAtCursorButtonAction,
MarkdownPartRenderer,
ToolCallPartRenderer,
} from './chat-response-renderer';
import {
AIEditorManager,
AIEditorSelectionResolver,
GitHubSelectionResolver,
TextFragmentSelectionResolver,
TypeDocSymbolSelectionResolver,
} from './chat-response-renderer/ai-editor-manager';
import { createChatViewTreeWidget } from './chat-tree-view';
import { ChatViewTreeWidget } from './chat-tree-view/chat-view-tree-widget';
Expand All @@ -37,6 +49,7 @@ import { ChatViewWidget } from './chat-view-widget';
import { ChatViewWidgetToolbarContribution } from './chat-view-widget-toolbar-contribution';
import { EditorPreviewManager } from '@theia/editor-preview/lib/browser/editor-preview-manager';
import { QuestionPartRenderer } from './chat-response-renderer/question-part-renderer';
import '../../src/browser/style/index.css';

export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
bindViewContribution(bind, AIChatContribution);
Expand Down Expand Up @@ -72,6 +85,12 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => {
bind(serviceIdentifier).to(ChatViewMenuContribution).inSingletonScope()
);

bindContributionProvider(bind, CodePartRendererAction);
bind(CopyToClipboardButtonAction).toSelf().inSingletonScope();
bind(CodePartRendererAction).toService(CopyToClipboardButtonAction);
bind(InsertCodeAtCursorButtonAction).toSelf().inSingletonScope();
bind(CodePartRendererAction).toService(InsertCodeAtCursorButtonAction);

bind(AIEditorManager).toSelf().inSingletonScope();
rebind(EditorManager).toService(AIEditorManager);
rebind(EditorPreviewManager).toService(AIEditorManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import {
ChatResponseContent,
CodeChatResponseContent,
} from '@theia/ai-chat/lib/common';
import { UntitledResourceResolver, URI } from '@theia/core';
import { ContributionProvider, UntitledResourceResolver, URI } from '@theia/core';
import { ContextMenuRenderer, TreeNode } from '@theia/core/lib/browser';
import { ClipboardService } from '@theia/core/lib/browser/clipboard-service';
import { inject, injectable } from '@theia/core/shared/inversify';
import { inject, injectable, named } from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
import { ReactNode } from '@theia/core/shared/react';
import { Position } from '@theia/core/shared/vscode-languageserver-protocol';
Expand All @@ -33,12 +32,29 @@ import { ChatResponsePartRenderer } from '../chat-response-part-renderer';
import { ChatViewTreeWidget, ResponseNode } from '../chat-tree-view/chat-view-tree-widget';
import { IMouseEvent } from '@theia/monaco-editor-core';

export const CodePartRendererAction = Symbol('CodePartRendererAction');
/**
* The CodePartRenderer offers to contribute arbitrary React nodes to the rendered code part.
* Technically anything can be rendered, however it is intended to be used for actions, like
* "Copy to Clipboard" or "Insert at Cursor".
*/
export interface CodePartRendererAction {
render(response: CodeChatResponseContent, parentNode: ResponseNode): ReactNode;
/**
* Determines if the action should be rendered for the given response.
*/
canRender?(response: CodeChatResponseContent, parentNode: ResponseNode): boolean;
/**
* The priority determines the order in which the actions are rendered.
* The default priorities are 10 and 20.
*/
priority: number;
}

@injectable()
export class CodePartRenderer
implements ChatResponsePartRenderer<CodeChatResponseContent> {

@inject(ClipboardService)
protected readonly clipboardService: ClipboardService;
@inject(EditorManager)
protected readonly editorManager: EditorManager;
@inject(UntitledResourceResolver)
Expand All @@ -49,6 +65,8 @@ export class CodePartRenderer
protected readonly languageService: MonacoLanguages;
@inject(ContextMenuRenderer)
protected readonly contextMenuRenderer: ContextMenuRenderer;
@inject(ContributionProvider) @named(CodePartRendererAction)
protected readonly codePartRendererActions: ContributionProvider<CodePartRendererAction>;

canHandle(response: ChatResponseContent): number {
if (CodeChatResponseContent.is(response)) {
Expand All @@ -59,14 +77,15 @@ export class CodePartRenderer

render(response: CodeChatResponseContent, parentNode: ResponseNode): ReactNode {
const language = response.language ? this.languageService.getExtension(response.language) : undefined;

return (
<div className="theia-CodePartRenderer-root">
<div className="theia-CodePartRenderer-top">
<div className="theia-CodePartRenderer-left">{this.renderTitle(response)}</div>
<div className="theia-CodePartRenderer-right">
<CopyToClipboardButton code={response.code} clipboardService={this.clipboardService} />
<InsertCodeAtCursorButton code={response.code} editorManager={this.editorManager} />
<div className="theia-CodePartRenderer-right theia-CodePartRenderer-actions">
{this.codePartRendererActions.getContributions()
.filter(action => action.canRender ? action.canRender(response, parentNode) : true)
.sort((a, b) => a.priority - b.priority)
.map(action => action.render(response, parentNode))}
</div>
</div>
<div className="theia-CodePartRenderer-separator"></div>
Expand Down Expand Up @@ -123,6 +142,16 @@ export class CodePartRenderer
}
}

@injectable()
export class CopyToClipboardButtonAction implements CodePartRendererAction {
@inject(ClipboardService)
protected readonly clipboardService: ClipboardService;
priority = 10;
render(response: CodeChatResponseContent): ReactNode {
return <CopyToClipboardButton key='copyToClipBoard' code={response.code} clipboardService={this.clipboardService} />;
}
}

const CopyToClipboardButton = (props: { code: string, clipboardService: ClipboardService }) => {
const { code, clipboardService } = props;
const copyCodeToClipboard = React.useCallback(() => {
Expand All @@ -131,6 +160,16 @@ const CopyToClipboardButton = (props: { code: string, clipboardService: Clipboar
return <div className='button codicon codicon-copy' title='Copy' role='button' onClick={copyCodeToClipboard}></div>;
};

@injectable()
export class InsertCodeAtCursorButtonAction implements CodePartRendererAction {
@inject(EditorManager)
protected readonly editorManager: EditorManager;
priority = 20;
render(response: CodeChatResponseContent): ReactNode {
return <InsertCodeAtCursorButton key='insertCodeAtCursor' code={response.code} editorManager={this.editorManager} />;
}
}

const InsertCodeAtCursorButton = (props: { code: string, editorManager: EditorManager }) => {
const { code, editorManager } = props;
const insertCode = React.useCallback(() => {
Expand Down
43 changes: 43 additions & 0 deletions packages/ai-chat/src/common/chat-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,18 +321,59 @@ export interface ChatResponse {
asString(): string;
}

/**
* The ChatResponseModel wraps the actual ChatResponse with additional information like the current state, progress messages, a unique id etc.
*/
export interface ChatResponseModel {
/**
* Use this to be notified for any change in the response model
*/
readonly onDidChange: Event<void>;
/**
* The unique identifier of the response model
*/
readonly id: string;
/**
* The unique identifier of the request model this response is associated with
*/
readonly requestId: string;
/**
* In case there are progress messages, then they will be stored here
*/
readonly progressMessages: ChatProgressMessage[];
/**
* The actual response content
*/
readonly response: ChatResponse;
/**
* Indicates whether this response is complete. No further changes are expected if 'true'.
*/
readonly isComplete: boolean;
/**
* Indicates whether this response is canceled. No further changes are expected if 'true'.
*/
readonly isCanceled: boolean;
/**
* Some agents might need to wait for user input to continue. This flag indicates that.
*/
readonly isWaitingForInput: boolean;
/**
* Indicates whether an error occurred when processing the response. No further changes are expected if 'true'.
*/
readonly isError: boolean;
/**
* The agent who produced the response content, if there is one.
*/
readonly agentId?: string
/**
* An optional error object that caused the response to be in an error state.
*/
readonly errorObject?: Error;
/**
* Some functionality might want to store some data associated with the response.
* This can be used to store and retrieve such data.
*/
readonly data: { [key: string]: unknown };
}

/**********************
Expand Down Expand Up @@ -750,6 +791,8 @@ class ChatResponseModelImpl implements ChatResponseModel {
protected readonly _onDidChangeEmitter = new Emitter<void>();
onDidChange: Event<void> = this._onDidChangeEmitter.event;

data = {};

protected _id: string;
protected _requestId: string;
protected _progressMessages: ChatProgressMessage[];
Expand Down
10 changes: 10 additions & 0 deletions packages/ai-scanoss/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: [
'../../configs/build.eslintrc.json'
],
parserOptions: {
tsconfigRootDir: __dirname,
project: 'tsconfig.json'
}
};
34 changes: 34 additions & 0 deletions packages/ai-scanoss/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<div align='center'>

<br />

<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />

<h2>ECLIPSE THEIA - SCAN OSS AI EXTENSION</h2>

<hr />

</div>

## Description

Integrates SCANOSS content scanning into the Chat View.
Whenever a code listing is rendered, a scan action is offered to the user.

Via the preferences the user can switch between manual and automatic scanning.

## Additional Information

- [Theia - GitHub](https://github.com/eclipse-theia/theia)
- [Theia - Website](https://theia-ide.org/)
- [SCAN OSS Website](https://www.scanoss.com/)

## License

- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)

## Trademark

"Theia" is a trademark of the Eclipse Foundation
<https://www.eclipse.org/theia>
Loading
Loading