Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
ChatService,
EditableChatRequestModel,
ParsedChatRequestAgentPart,
ParsedChatRequestFunctionPart,
ParsedChatRequestVariablePart,
type ChatRequest,
type ChatHierarchyBranch,
Expand Down Expand Up @@ -808,7 +809,7 @@ const ChatRequestRender = (
<div className="theia-RequestNode">
<p>
{parts.map((part, index) => {
if (part instanceof ParsedChatRequestAgentPart || part instanceof ParsedChatRequestVariablePart) {
if (part instanceof ParsedChatRequestAgentPart || part instanceof ParsedChatRequestVariablePart || part instanceof ParsedChatRequestFunctionPart) {
let description = undefined;
let className = '';
if (part instanceof ParsedChatRequestAgentPart) {
Expand All @@ -817,6 +818,9 @@ const ChatRequestRender = (
} else if (part instanceof ParsedChatRequestVariablePart) {
description = variableService.getVariable(part.variableName)?.description;
className = 'theia-RequestNode-VariableLabel';
} else if (part instanceof ParsedChatRequestFunctionPart) {
description = part.toolRequest?.description;
className = 'theia-RequestNode-FunctionLabel';
}
return (
<HoverableLabel
Expand Down
3 changes: 2 additions & 1 deletion packages/ai-chat-ui/src/browser/style/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ div:last-child > .theia-ChatNode {
}

.theia-RequestNode .theia-RequestNode-AgentLabel,
.theia-RequestNode .theia-RequestNode-VariableLabel {
.theia-RequestNode .theia-RequestNode-VariableLabel,
.theia-RequestNode .theia-RequestNode-FunctionLabel {
padding: calc(var(--theia-ui-padding) * 2 / 3);
padding-top: 0px;
padding-bottom: 0px;
Expand Down
99 changes: 68 additions & 31 deletions packages/ai-chat/src/common/chat-request-parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { ChatContext, ChatRequest } from './chat-model';
import { expect } from 'chai';
import { AIVariable, DefaultAIVariableService, ResolvedAIVariable, ToolInvocationRegistryImpl, ToolRequest } from '@theia/ai-core';
import { ILogger, Logger } from '@theia/core';
import { ParsedChatRequestTextPart, ParsedChatRequestVariablePart } from './parsed-chat-request';
import { ParsedChatRequestAgentPart, ParsedChatRequestFunctionPart, ParsedChatRequestTextPart, ParsedChatRequestVariablePart } from './parsed-chat-request';

describe('ChatRequestParserImpl', () => {
const chatAgentService = sinon.createStubInstance(ChatAgentServiceImpl);
Expand All @@ -42,10 +42,11 @@ describe('ChatRequestParserImpl', () => {
};
const context: ChatContext = { variables: [] };
const result = await parser.parseChatRequest(req, ChatAgentLocation.Panel, context);
expect(result.parts).to.deep.contain({
text: 'What is the best pizza topping?',
range: { start: 0, endExclusive: 31 }
});
expect(result.parts.length).to.equal(1);
const part = result.parts[0] as ParsedChatRequestTextPart;
expect(part.kind).to.equal('text');
expect(part.text).to.equal('What is the best pizza topping?');
expect(part.range).to.deep.equal({ start: 0, endExclusive: 31 });
});

it('parses text with variable name', async () => {
Expand All @@ -54,19 +55,23 @@ describe('ChatRequestParserImpl', () => {
};
const context: ChatContext = { variables: [] };
const result = await parser.parseChatRequest(req, ChatAgentLocation.Panel, context);
expect(result).to.deep.contain({
parts: [{
text: 'What is the ',
range: { start: 0, endExclusive: 12 }
}, {
variableName: 'best',
variableArg: undefined,
range: { start: 12, endExclusive: 17 }
}, {
text: ' pizza topping?',
range: { start: 17, endExclusive: 32 }
}]
});
expect(result.parts.length).to.equal(3);

const textPart1 = result.parts[0] as ParsedChatRequestTextPart;
expect(textPart1.kind).to.equal('text');
expect(textPart1.text).to.equal('What is the ');
expect(textPart1.range).to.deep.equal({ start: 0, endExclusive: 12 });

const varPart = result.parts[1] as ParsedChatRequestVariablePart;
expect(varPart.kind).to.equal('var');
expect(varPart.variableName).to.equal('best');
expect(varPart.variableArg).to.be.undefined;
expect(varPart.range).to.deep.equal({ start: 12, endExclusive: 17 });

const textPart2 = result.parts[2] as ParsedChatRequestTextPart;
expect(textPart2.kind).to.equal('text');
expect(textPart2.text).to.equal(' pizza topping?');
expect(textPart2.range).to.deep.equal({ start: 17, endExclusive: 32 });
});

it('parses text with variable name with argument', async () => {
Expand All @@ -75,19 +80,23 @@ describe('ChatRequestParserImpl', () => {
};
const context: ChatContext = { variables: [] };
const result = await parser.parseChatRequest(req, ChatAgentLocation.Panel, context);
expect(result).to.deep.contain({
parts: [{
text: 'What is the ',
range: { start: 0, endExclusive: 12 }
}, {
variableName: 'best',
variableArg: 'by-poll',
range: { start: 12, endExclusive: 25 }
}, {
text: ' pizza topping?',
range: { start: 25, endExclusive: 40 }
}]
});
expect(result.parts.length).to.equal(3);

const textPart1 = result.parts[0] as ParsedChatRequestTextPart;
expect(textPart1.kind).to.equal('text');
expect(textPart1.text).to.equal('What is the ');
expect(textPart1.range).to.deep.equal({ start: 0, endExclusive: 12 });

const varPart = result.parts[1] as ParsedChatRequestVariablePart;
expect(varPart.kind).to.equal('var');
expect(varPart.variableName).to.equal('best');
expect(varPart.variableArg).to.equal('by-poll');
expect(varPart.range).to.deep.equal({ start: 12, endExclusive: 25 });

const textPart2 = result.parts[2] as ParsedChatRequestTextPart;
expect(textPart2.kind).to.equal('text');
expect(textPart2.text).to.equal(' pizza topping?');
expect(textPart2.range).to.deep.equal({ start: 25, endExclusive: 40 });
});

it('parses text with variable name with numeric argument', async () => {
Expand Down Expand Up @@ -265,4 +274,32 @@ describe('ChatRequestParserImpl', () => {
const varPart = result.parts[0] as ParsedChatRequestVariablePart;
expect(varPart.variableArg).to.equal('cmd|"arg with \\"quote\\"" other');
});

describe('parsed chat request part kind assignments', () => {
it('ParsedChatRequestTextPart has kind assigned at runtime', () => {
const part = new ParsedChatRequestTextPart({ start: 0, endExclusive: 5 }, 'hello');
expect(part.kind).to.equal('text');
});

it('ParsedChatRequestVariablePart has kind assigned at runtime', () => {
const part = new ParsedChatRequestVariablePart({ start: 0, endExclusive: 5 }, 'varName', undefined);
expect(part.kind).to.equal('var');
});

it('ParsedChatRequestFunctionPart has kind assigned at runtime', () => {
const toolRequest: ToolRequest = {
id: 'testTool',
name: 'Test Tool',
handler: async () => undefined,
parameters: { type: 'object', properties: {} }
};
const part = new ParsedChatRequestFunctionPart({ start: 0, endExclusive: 5 }, toolRequest);
expect(part.kind).to.equal('function');
});

it('ParsedChatRequestAgentPart has kind assigned at runtime', () => {
const part = new ParsedChatRequestAgentPart({ start: 0, endExclusive: 5 }, 'agentId', 'agentName');
expect(part.kind).to.equal('agent');
});
});
});
8 changes: 4 additions & 4 deletions packages/ai-chat/src/common/parsed-chat-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export interface ParsedChatRequestPart {
}

export class ParsedChatRequestTextPart implements ParsedChatRequestPart {
readonly kind: 'text';
readonly kind = 'text';

constructor(readonly range: OffsetRange, readonly text: string) { }

Expand All @@ -69,7 +69,7 @@ export class ParsedChatRequestTextPart implements ParsedChatRequestPart {
}

export class ParsedChatRequestVariablePart implements ParsedChatRequestPart {
readonly kind: 'var';
readonly kind = 'var';

public resolution: ResolvedAIVariable;

Expand All @@ -86,7 +86,7 @@ export class ParsedChatRequestVariablePart implements ParsedChatRequestPart {
}

export class ParsedChatRequestFunctionPart implements ParsedChatRequestPart {
readonly kind: 'function';
readonly kind = 'function';
constructor(readonly range: OffsetRange, readonly toolRequest: ToolRequest) { }

get text(): string {
Expand All @@ -99,7 +99,7 @@ export class ParsedChatRequestFunctionPart implements ParsedChatRequestPart {
}

export class ParsedChatRequestAgentPart implements ParsedChatRequestPart {
readonly kind: 'agent';
readonly kind = 'agent';
constructor(readonly range: OffsetRange, readonly agentId: string, readonly agentName: string) { }

get text(): string {
Expand Down
Loading