@theia/ai-chat 1.74.0-next.9 → 1.74.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/agent-delegation-tool.js +6 -7
- package/lib/browser/agent-delegation-tool.js.map +1 -1
- package/lib/browser/agent-delegation-tool.spec.js +13 -0
- package/lib/browser/agent-delegation-tool.spec.js.map +1 -1
- package/lib/browser/chat-request-command-resolution.spec.d.ts +2 -0
- package/lib/browser/chat-request-command-resolution.spec.d.ts.map +1 -0
- package/lib/browser/chat-request-command-resolution.spec.js +94 -0
- package/lib/browser/chat-request-command-resolution.spec.js.map +1 -0
- package/lib/browser/chat-session-store-impl.d.ts.map +1 -1
- package/lib/browser/chat-session-store-impl.js +2 -0
- package/lib/browser/chat-session-store-impl.js.map +1 -1
- package/lib/browser/chat-session-store-impl.spec.js +51 -2
- package/lib/browser/chat-session-store-impl.spec.js.map +1 -1
- package/lib/browser/chat-tool-preference-bindings.d.ts +18 -8
- package/lib/browser/chat-tool-preference-bindings.d.ts.map +1 -1
- package/lib/browser/chat-tool-preference-bindings.js +27 -28
- package/lib/browser/chat-tool-preference-bindings.js.map +1 -1
- package/lib/browser/chat-tool-preference-bindings.spec.js +43 -46
- package/lib/browser/chat-tool-preference-bindings.spec.js.map +1 -1
- package/lib/common/chat-agents.d.ts +8 -0
- package/lib/common/chat-agents.d.ts.map +1 -1
- package/lib/common/chat-agents.js +35 -1
- package/lib/common/chat-agents.js.map +1 -1
- package/lib/common/chat-agents.spec.js +94 -0
- package/lib/common/chat-agents.spec.js.map +1 -1
- package/lib/common/chat-auto-save.spec.js +13 -0
- package/lib/common/chat-auto-save.spec.js.map +1 -1
- package/lib/common/chat-content-deserializer.d.ts.map +1 -1
- package/lib/common/chat-content-deserializer.js +4 -0
- package/lib/common/chat-content-deserializer.js.map +1 -1
- package/lib/common/chat-model-serialization.d.ts +12 -1
- package/lib/common/chat-model-serialization.d.ts.map +1 -1
- package/lib/common/chat-model-serialization.js.map +1 -1
- package/lib/common/chat-model-serialization.spec.js +29 -0
- package/lib/common/chat-model-serialization.spec.js.map +1 -1
- package/lib/common/chat-model.d.ts +105 -2
- package/lib/common/chat-model.d.ts.map +1 -1
- package/lib/common/chat-model.js +159 -3
- package/lib/common/chat-model.js.map +1 -1
- package/lib/common/chat-model.spec.d.ts +2 -0
- package/lib/common/chat-model.spec.d.ts.map +1 -0
- package/lib/common/chat-model.spec.js +42 -0
- package/lib/common/chat-model.spec.js.map +1 -0
- package/lib/common/chat-request-parser.d.ts +9 -1
- package/lib/common/chat-request-parser.d.ts.map +1 -1
- package/lib/common/chat-request-parser.js +54 -3
- package/lib/common/chat-request-parser.js.map +1 -1
- package/lib/common/chat-request-parser.spec.js +333 -0
- package/lib/common/chat-request-parser.spec.js.map +1 -1
- package/lib/common/chat-response-model.spec.js +31 -0
- package/lib/common/chat-response-model.spec.js.map +1 -1
- package/lib/common/chat-service-deletion.spec.js +43 -0
- package/lib/common/chat-service-deletion.spec.js.map +1 -1
- package/lib/common/chat-service-pinned-agent.spec.js +52 -2
- package/lib/common/chat-service-pinned-agent.spec.js.map +1 -1
- package/lib/common/chat-service-session-events.spec.d.ts +2 -0
- package/lib/common/chat-service-session-events.spec.d.ts.map +1 -0
- package/lib/common/chat-service-session-events.spec.js +130 -0
- package/lib/common/chat-service-session-events.spec.js.map +1 -0
- package/lib/common/chat-service.d.ts +3 -0
- package/lib/common/chat-service.d.ts.map +1 -1
- package/lib/common/chat-service.js +60 -6
- package/lib/common/chat-service.js.map +1 -1
- package/lib/common/chat-service.spec.d.ts +2 -0
- package/lib/common/chat-service.spec.d.ts.map +1 -0
- package/lib/common/chat-service.spec.js +177 -0
- package/lib/common/chat-service.spec.js.map +1 -0
- package/lib/common/chat-session-status.spec.d.ts +2 -0
- package/lib/common/chat-session-status.spec.d.ts.map +1 -0
- package/lib/common/chat-session-status.spec.js +213 -0
- package/lib/common/chat-session-status.spec.js.map +1 -0
- package/lib/common/chat-session-store.d.ts +8 -0
- package/lib/common/chat-session-store.d.ts.map +1 -1
- package/lib/common/tool-call-response-content.spec.js +36 -0
- package/lib/common/tool-call-response-content.spec.js.map +1 -1
- package/package.json +11 -11
- package/src/browser/agent-delegation-tool.spec.ts +16 -0
- package/src/browser/agent-delegation-tool.ts +7 -7
- package/src/browser/chat-request-command-resolution.spec.ts +117 -0
- package/src/browser/chat-session-store-impl.spec.ts +62 -2
- package/src/browser/chat-session-store-impl.ts +2 -0
- package/src/browser/chat-tool-preference-bindings.spec.ts +43 -48
- package/src/browser/chat-tool-preference-bindings.ts +42 -30
- package/src/common/chat-agents.spec.ts +112 -2
- package/src/common/chat-agents.ts +44 -1
- package/src/common/chat-auto-save.spec.ts +18 -1
- package/src/common/chat-content-deserializer.ts +11 -0
- package/src/common/chat-model-serialization.spec.ts +38 -0
- package/src/common/chat-model-serialization.ts +12 -1
- package/src/common/chat-model.spec.ts +42 -0
- package/src/common/chat-model.ts +241 -3
- package/src/common/chat-request-parser.spec.ts +401 -1
- package/src/common/chat-request-parser.ts +60 -5
- package/src/common/chat-response-model.spec.ts +41 -1
- package/src/common/chat-service-deletion.spec.ts +52 -0
- package/src/common/chat-service-pinned-agent.spec.ts +58 -2
- package/src/common/chat-service-session-events.spec.ts +161 -0
- package/src/common/chat-service.spec.ts +211 -0
- package/src/common/chat-service.ts +64 -8
- package/src/common/chat-session-status.spec.ts +280 -0
- package/src/common/chat-session-store.ts +8 -0
- package/src/common/tool-call-response-content.spec.ts +42 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-model.spec.d.ts","sourceRoot":"","sources":["../../src/common/chat-model.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
const chai_1 = require("chai");
|
|
19
|
+
const chat_model_1 = require("./chat-model");
|
|
20
|
+
describe('CompactionChatResponseContent', () => {
|
|
21
|
+
it('round-trips through serialization', () => {
|
|
22
|
+
const original = new chat_model_1.CompactionChatResponseContentImpl('anthropic', { block: 'opaque' }, 'summary text');
|
|
23
|
+
const serialized = original.toSerializable();
|
|
24
|
+
(0, chai_1.expect)(serialized.kind).to.equal('compaction');
|
|
25
|
+
const restored = new chat_model_1.CompactionChatResponseContentImpl(serialized.data.provider, serialized.data.data, serialized.data.summary);
|
|
26
|
+
(0, chai_1.expect)(restored.provider).to.equal('anthropic');
|
|
27
|
+
(0, chai_1.expect)(restored.summary).to.equal('summary text');
|
|
28
|
+
(0, chai_1.expect)(restored.data).to.deep.equal({ block: 'opaque' });
|
|
29
|
+
});
|
|
30
|
+
it('produces a compaction language model message', () => {
|
|
31
|
+
const content = new chat_model_1.CompactionChatResponseContentImpl('openai-responses', { item: 'x' });
|
|
32
|
+
const message = content.toLanguageModelMessage();
|
|
33
|
+
(0, chai_1.expect)(message).to.deep.equal({ actor: 'ai', type: 'compaction', provider: 'openai-responses', data: { item: 'x' }, summary: undefined });
|
|
34
|
+
});
|
|
35
|
+
it('is excluded from plain-text history but offers a display string', () => {
|
|
36
|
+
const content = new chat_model_1.CompactionChatResponseContentImpl('anthropic', {}, 'sum');
|
|
37
|
+
(0, chai_1.expect)(content.asString()).to.equal(undefined);
|
|
38
|
+
(0, chai_1.expect)(content.asDisplayString()).to.equal('sum');
|
|
39
|
+
(0, chai_1.expect)(chat_model_1.CompactionChatResponseContent.is(content)).to.equal(true);
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=chat-model.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-model.spec.js","sourceRoot":"","sources":["../../src/common/chat-model.spec.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;;AAEhF,+BAA8B;AAC9B,6CAAgG;AAEhG,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC3C,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QACzC,MAAM,QAAQ,GAAG,IAAI,8CAAiC,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,cAAc,CAAC,CAAC;QACzG,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,EAAE,CAAC;QAC7C,IAAA,aAAM,EAAC,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,IAAI,8CAAiC,CAClD,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC7E,IAAA,aAAM,EAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAChD,IAAA,aAAM,EAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAClD,IAAA,aAAM,EAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACpD,MAAM,OAAO,GAAG,IAAI,8CAAiC,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;QACzF,MAAM,OAAO,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC;QACjD,IAAA,aAAM,EAAC,OAAO,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9I,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACvE,MAAM,OAAO,GAAG,IAAI,8CAAiC,CAAC,WAAW,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;QAC9E,IAAA,aAAM,EAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC/C,IAAA,aAAM,EAAC,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAClD,IAAA,aAAM,EAAC,0CAA6B,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -2,7 +2,7 @@ import { ChatAgentService } from './chat-agent-service';
|
|
|
2
2
|
import { ChatAgentLocation } from './chat-agents';
|
|
3
3
|
import { ChatContext, ChatRequest } from './chat-model';
|
|
4
4
|
import { ParsedChatRequestVariablePart, ParsedChatRequest, ParsedChatRequestPart } from './parsed-chat-request';
|
|
5
|
-
import { AIVariable, AIVariableService, ToolInvocationRegistry, ToolRequest } from '@theia/ai-core';
|
|
5
|
+
import { AIVariable, AIVariableService, PromptService, ToolInvocationRegistry, ToolRequest } from '@theia/ai-core';
|
|
6
6
|
import { ILogger } from '@theia/core';
|
|
7
7
|
export declare const ChatRequestParser: unique symbol;
|
|
8
8
|
export interface ChatRequestParser {
|
|
@@ -13,6 +13,7 @@ export declare class ChatRequestParserImpl implements ChatRequestParser {
|
|
|
13
13
|
private readonly variableService;
|
|
14
14
|
private readonly toolInvocationRegistry;
|
|
15
15
|
private readonly logger;
|
|
16
|
+
protected readonly promptService: PromptService;
|
|
16
17
|
constructor(agentService: ChatAgentService, variableService: AIVariableService, toolInvocationRegistry: ToolInvocationRegistry, logger: ILogger);
|
|
17
18
|
parseChatRequest(request: ChatRequest, location: ChatAgentLocation, context: ChatContext): Promise<ParsedChatRequest>;
|
|
18
19
|
protected parseParts(request: ChatRequest, location: ChatAgentLocation): {
|
|
@@ -34,6 +35,13 @@ export declare class ChatRequestParserImpl implements ChatRequestParser {
|
|
|
34
35
|
* The prompt variable resolver will handle the actual resolution.
|
|
35
36
|
*/
|
|
36
37
|
protected tryToParseCommand(message: string, offset: number, _parts: ReadonlyArray<ParsedChatRequestPart>): ParsedChatRequestVariablePart | undefined;
|
|
38
|
+
private findNextCommandOffset;
|
|
39
|
+
/**
|
|
40
|
+
* Whether a `/name` token should be treated as a command. Only names that actually resolve to a
|
|
41
|
+
* command or prompt fragment are accepted, which keeps unknown `/word` tokens (e.g. `/tmp`,
|
|
42
|
+
* `/path/to/file`) as plain text.
|
|
43
|
+
*/
|
|
44
|
+
protected isCommandCandidate(commandName: string): boolean;
|
|
37
45
|
private tryToParseFunction;
|
|
38
46
|
}
|
|
39
47
|
//# sourceMappingURL=chat-request-parser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-request-parser.d.ts","sourceRoot":"","sources":["../../src/common/chat-request-parser.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAMH,6BAA6B,EAI7B,iBAAiB,EACjB,qBAAqB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACH,UAAU,EAAE,iBAAiB,EAAmF,sBAAsB,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"chat-request-parser.d.ts","sourceRoot":"","sources":["../../src/common/chat-request-parser.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAMH,6BAA6B,EAI7B,iBAAiB,EACjB,qBAAqB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACH,UAAU,EAAE,iBAAiB,EAAmF,aAAa,EAAE,sBAAsB,EAAE,WAAW,EACrK,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AActC,eAAO,MAAM,iBAAiB,eAA8B,CAAC;AAC7D,MAAM,WAAW,iBAAiB;IAC9B,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACzH;AAQD,qBACa,qBAAsB,YAAW,iBAAiB;IAM7B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAC3B,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAN5C,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;gBAGD,YAAY,EAAE,gBAAgB,EAC7B,eAAe,EAAE,iBAAiB,EAC7B,sBAAsB,EAAE,sBAAsB,EAC7D,MAAM,EAAE,OAAO;IAG/C,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAiC3H,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,iBAAiB,GAAG;QACrE,KAAK,EAAE,qBAAqB,EAAE,CAAC;QAC/B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACvC,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAC7B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;KACtC;IA+FD;;OAEG;IACH,OAAO,CAAC,8BAA8B;IAkBtC,OAAO,CAAC,eAAe;IAqCvB,OAAO,CAAC,kBAAkB;IAiB1B;;;;;OAKG;IACH,SAAS,CAAC,iBAAiB,CACvB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,aAAa,CAAC,qBAAqB,CAAC,GAC7C,6BAA6B,GAAG,SAAS;IAsC5C,OAAO,CAAC,qBAAqB;IAY7B;;;;OAIG;IACH,SAAS,CAAC,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAI1D,OAAO,CAAC,kBAAkB;CAkB7B"}
|
|
@@ -33,7 +33,11 @@ const agentReg = /^@([\w_\-\.]+)(?=(\s|$|\b))/i; // An @-agent
|
|
|
33
33
|
const functionReg = /^~(\??[\w_\-\.]+)(?=(\s|$|\b))/i;
|
|
34
34
|
const functionPromptFormatReg = /^\~\{\s*(.*?)\s*\}/i;
|
|
35
35
|
const variableReg = /^#([\w_\-]+)(?::([\w_\-_\/\\.:]+))?(?=(\s|$|\b))/i; // A #-variable with an optional : arg (#file:workspace/path/name.ext)
|
|
36
|
-
|
|
36
|
+
// A /-command (/commandname) with optional arguments parsed separately. The command name must be
|
|
37
|
+
// terminated by whitespace or the end of the input, so that path segments such as `/home/user` are
|
|
38
|
+
// not mistaken for a command.
|
|
39
|
+
const commandReg = /^\/([\w_\-]+)(?=\s|$)/;
|
|
40
|
+
const nextCommandReg = /\s+\/([\w_\-]+)(?=\s|$)/g;
|
|
37
41
|
exports.ChatRequestParser = Symbol('ChatRequestParser');
|
|
38
42
|
function offsetRange(start, endExclusive) {
|
|
39
43
|
if (start > endExclusive) {
|
|
@@ -131,6 +135,7 @@ let ChatRequestParserImpl = class ChatRequestParserImpl {
|
|
|
131
135
|
parts.push(new parsed_chat_request_1.ParsedChatRequestTextPart(offsetRange(previousPartEnd, i), message.slice(previousPartEnd, i)));
|
|
132
136
|
}
|
|
133
137
|
parts.push(newPart);
|
|
138
|
+
i = newPart.range.endExclusive - 1;
|
|
134
139
|
}
|
|
135
140
|
}
|
|
136
141
|
const lastPart = parts.at(-1);
|
|
@@ -206,11 +211,53 @@ let ChatRequestParserImpl = class ChatRequestParserImpl {
|
|
|
206
211
|
if (!nextCommandMatch) {
|
|
207
212
|
return;
|
|
208
213
|
}
|
|
209
|
-
const [
|
|
210
|
-
|
|
214
|
+
const [commandText, commandName] = nextCommandMatch;
|
|
215
|
+
if (!this.isCommandCandidate(commandName)) {
|
|
216
|
+
// Not a command we know about, so leave the text alone. Otherwise anything the user
|
|
217
|
+
// types after a `/word` token, e.g. a Unix path, would be swallowed as command
|
|
218
|
+
// arguments and silently dropped when the non-existing command fails to resolve.
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
let commandEnd = commandText.length;
|
|
222
|
+
let commandArgs;
|
|
223
|
+
// Arguments never span multiple lines: a command only consumes the remainder of its own line.
|
|
224
|
+
const lineBreakOffset = message.indexOf('\n', commandEnd);
|
|
225
|
+
const lineEnd = lineBreakOffset === -1 ? message.length : lineBreakOffset;
|
|
226
|
+
const nextCommandOffset = this.findNextCommandOffset(message, commandEnd, lineEnd);
|
|
227
|
+
const argsEnd = nextCommandOffset ?? lineEnd;
|
|
228
|
+
const rawArgs = message.slice(commandEnd, argsEnd);
|
|
229
|
+
const args = rawArgs.trim();
|
|
230
|
+
if (args) {
|
|
231
|
+
commandArgs = args;
|
|
232
|
+
// Advance the consumed range only up to the end of the trimmed argument, not up to the
|
|
233
|
+
// next command. This keeps the whitespace between the argument and a following command
|
|
234
|
+
// out of this part's range, so parseParts emits it as a separator text part. Otherwise
|
|
235
|
+
// the two resolved prompt fragments would run into each other with no space between them.
|
|
236
|
+
commandEnd = argsEnd - (rawArgs.length - rawArgs.trimEnd().length);
|
|
237
|
+
}
|
|
238
|
+
const commandRange = offsetRange(offset, offset + commandEnd);
|
|
211
239
|
const variableArg = commandArgs ? `${commandName}|${commandArgs}` : commandName;
|
|
212
240
|
return new parsed_chat_request_1.ParsedChatRequestVariablePart(commandRange, 'prompt', variableArg);
|
|
213
241
|
}
|
|
242
|
+
findNextCommandOffset(message, startOffset, endOffset) {
|
|
243
|
+
nextCommandReg.lastIndex = startOffset;
|
|
244
|
+
let match = nextCommandReg.exec(message);
|
|
245
|
+
while (match && match.index < endOffset) {
|
|
246
|
+
if (this.isCommandCandidate(match[1])) {
|
|
247
|
+
return match.index + match[0].indexOf(parsed_chat_request_1.chatSubcommandLeader);
|
|
248
|
+
}
|
|
249
|
+
match = nextCommandReg.exec(message);
|
|
250
|
+
}
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Whether a `/name` token should be treated as a command. Only names that actually resolve to a
|
|
255
|
+
* command or prompt fragment are accepted, which keeps unknown `/word` tokens (e.g. `/tmp`,
|
|
256
|
+
* `/path/to/file`) as plain text.
|
|
257
|
+
*/
|
|
258
|
+
isCommandCandidate(commandName) {
|
|
259
|
+
return this.promptService.isKnownCommand(commandName);
|
|
260
|
+
}
|
|
214
261
|
tryToParseFunction(message, offset) {
|
|
215
262
|
// Support both the chat and prompt formats for functions
|
|
216
263
|
const nextFunctionMatch = message.match(functionPromptFormatReg) || message.match(functionReg);
|
|
@@ -228,6 +275,10 @@ let ChatRequestParserImpl = class ChatRequestParserImpl {
|
|
|
228
275
|
}
|
|
229
276
|
};
|
|
230
277
|
exports.ChatRequestParserImpl = ChatRequestParserImpl;
|
|
278
|
+
tslib_1.__decorate([
|
|
279
|
+
(0, inversify_1.inject)(ai_core_1.PromptService),
|
|
280
|
+
tslib_1.__metadata("design:type", Object)
|
|
281
|
+
], ChatRequestParserImpl.prototype, "promptService", void 0);
|
|
231
282
|
exports.ChatRequestParserImpl = ChatRequestParserImpl = tslib_1.__decorate([
|
|
232
283
|
(0, inversify_1.injectable)(),
|
|
233
284
|
tslib_1.__param(0, (0, inversify_1.inject)(chat_agent_service_1.ChatAgentService)),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-request-parser.js","sourceRoot":"","sources":["../../src/common/chat-request-parser.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF;;;gGAGgG;AAChG,oKAAoK;;;;AAEpK,4DAAkE;AAClE,6DAAwD;AAGxD,+DAY+B;AAC/B,4CAEwB;AACxB,sCAAsC;AAEtC,MAAM,QAAQ,GAAG,8BAA8B,CAAC,CAAC,aAAa;AAC9D,yEAAyE;AACzE,yEAAyE;AACzE,MAAM,WAAW,GAAG,iCAAiC,CAAC;AACtD,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AACtD,MAAM,WAAW,GAAG,mDAAmD,CAAC,CAAC,sEAAsE;AAC/I,MAAM,UAAU,GAAG,
|
|
1
|
+
{"version":3,"file":"chat-request-parser.js","sourceRoot":"","sources":["../../src/common/chat-request-parser.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,yCAAyC;AACzC,EAAE;AACF,2EAA2E;AAC3E,mEAAmE;AACnE,wCAAwC;AACxC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,yDAAyD;AACzD,uDAAuD;AACvD,EAAE;AACF,gFAAgF;AAChF,gFAAgF;AAChF;;;gGAGgG;AAChG,oKAAoK;;;;AAEpK,4DAAkE;AAClE,6DAAwD;AAGxD,+DAY+B;AAC/B,4CAEwB;AACxB,sCAAsC;AAEtC,MAAM,QAAQ,GAAG,8BAA8B,CAAC,CAAC,aAAa;AAC9D,yEAAyE;AACzE,yEAAyE;AACzE,MAAM,WAAW,GAAG,iCAAiC,CAAC;AACtD,MAAM,uBAAuB,GAAG,qBAAqB,CAAC;AACtD,MAAM,WAAW,GAAG,mDAAmD,CAAC,CAAC,sEAAsE;AAC/I,iGAAiG;AACjG,mGAAmG;AACnG,8BAA8B;AAC9B,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAC3C,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAErC,QAAA,iBAAiB,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAC;AAK7D,SAAS,WAAW,CAAC,KAAa,EAAE,YAAoB;IACpD,IAAI,KAAK,GAAG,YAAY,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,wBAAwB,KAAK,iBAAiB,YAAY,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;AACnC,CAAC;AAEM,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAK9B,YAC+C,YAA8B,EAC7B,eAAkC,EAC7B,sBAA8C,EAC7D,MAAe;QAHN,iBAAY,GAAZ,YAAY,CAAkB;QAC7B,oBAAe,GAAf,eAAe,CAAmB;QAC7B,2BAAsB,GAAtB,sBAAsB,CAAwB;QAC7D,WAAM,GAAN,MAAM,CAAS;IACjD,CAAC;IAEL,KAAK,CAAC,gBAAgB,CAAC,OAAoB,EAAE,QAA2B,EAAE,OAAoB;QAC1F,+BAA+B;QAC/B,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAEpF,4DAA4D;QAC5D,yDAAyD;QACzD,oFAAoF;QACpF,wFAAwF;QACxF,MAAM,aAAa,GAAG,IAAA,sCAA4B,GAAE,CAAC;QACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,IAAI,YAAY,mDAA6B,EAAE,CAAC;gBAChD,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,eAAe,CAC/D,EAAE,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,EACtD,OAAO,EACP,aAAa,CAChB,CAAC;gBACF,IAAI,gBAAgB,EAAE,CAAC;oBACnB,IAAI,CAAC,UAAU,GAAG,gBAAgB,CAAC;oBACnC,8CAA8C;oBAC9C,IAAI,CAAC,8BAA8B,CAAC,gBAAgB,CAAC,KAAK,EAAE,YAAY,EAAE,eAAe,CAAC,CAAC;gBAC/F,CAAC;qBAAM,CAAC;oBACJ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,8BAA8B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,QAAQ,EAAE,CAAC,CAAC;gBACzI,CAAC;YACL,CAAC;QACL,CAAC;QAED,qFAAqF;QACrF,kFAAkF;QAClF,MAAM,iBAAiB,GAAG,MAAM,IAAA,mCAAyB,EAAC,aAAa,CAAC,CAAC;QAEzE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC3F,CAAC;IAES,UAAU,CAAC,OAAoB,EAAE,QAA2B;QAMlE,MAAM,KAAK,GAA4B,EAAE,CAAC;QAC1C,MAAM,SAAS,GAAG,IAAI,GAAG,EAAsB,CAAC;QAChD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAuB,CAAC;QACpD,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;QAC/D,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;QAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,OAA0C,CAAC;YAE/C,IAAI,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtC,IAAI,IAAI,KAAK,0CAAoB,EAAE,CAAC;oBAChC,sFAAsF;oBACtF,MAAM,WAAW,GAAG,IAAI,CAAC,iBAAiB,CACtC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAChB,CAAC,EACD,KAAK,CACR,CAAC;oBACF,IAAI,WAAW,EAAE,CAAC;wBACd,OAAO,GAAG,WAAW,CAAC;wBACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;wBAC5E,IAAI,QAAQ,EAAE,CAAC;4BACX,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;wBAC3C,CAAC;oBACL,CAAC;gBACL,CAAC;qBAAM,IAAI,IAAI,KAAK,wCAAkB,EAAE,CAAC;oBACrC,MAAM,YAAY,GAAG,IAAI,CAAC,kBAAkB,CACxC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAChB,CAAC,CACJ,CAAC;oBACF,OAAO,GAAG,YAAY,CAAC;oBACvB,IAAI,YAAY,EAAE,CAAC;wBACf,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;wBACxE,IAAI,YAAY,CAAC,QAAQ,EAAE,CAAC;4BACxB,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;wBACrD,CAAC;oBACL,CAAC;gBACL,CAAC;qBAAM,IAAI,IAAI,KAAK,wCAAkB,EAAE,CAAC;oBACrC,MAAM,YAAY,GAAG,IAAI,CAAC,kBAAkB,CACxC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAChB,CAAC,EACD,KAAK,CACR,CAAC;oBACF,OAAO,GAAG,YAAY,CAAC;oBACvB,IAAI,YAAY,EAAE,CAAC;wBACf,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;wBAC7E,IAAI,QAAQ,EAAE,CAAC;4BACX,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;wBAC3C,CAAC;oBACL,CAAC;gBACL,CAAC;qBAAM,IAAI,IAAI,KAAK,qCAAe,EAAE,CAAC;oBAClC,OAAO,GAAG,IAAI,CAAC,eAAe,CAC1B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAChB,CAAC,EACD,KAAK,EACL,QAAQ,CACX,CAAC;gBACN,CAAC;YACL,CAAC;YAED,IAAI,OAAO,EAAE,CAAC;gBACV,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACV,iFAAiF;oBACjF,MAAM,YAAY,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;oBAClC,MAAM,eAAe,GAAG,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;oBAC9D,KAAK,CAAC,IAAI,CACN,IAAI,+CAAyB,CACzB,WAAW,CAAC,eAAe,EAAE,CAAC,CAAC,EAC/B,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,CAAC,CAAC,CACpC,CACJ,CAAC;gBACN,CAAC;gBAED,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACpB,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC;YACvC,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,WAAW,GAAG,QAAQ,EAAE,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;QACtD,IAAI,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CACN,IAAI,+CAAyB,CACzB,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,EACxC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,MAAM,CAAC,CAC7C,CACJ,CAAC;QACN,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;IAC/D,CAAC;IAED;;OAEG;IACK,8BAA8B,CAAC,IAAY,EAAE,YAAsC,EAAE,eAA4B;QACrH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAE5B,+CAA+C;YAC/C,IAAI,IAAI,KAAK,wCAAkB,EAAE,CAAC;gBAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC/D,IAAI,YAAY,EAAE,CAAC;oBACf,8CAA8C;oBAC9C,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;oBACxE,IAAI,YAAY,CAAC,QAAQ,EAAE,CAAC;wBACxB,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;oBACrD,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAEO,eAAe,CACnB,OAAe,EACf,MAAc,EACd,KAA2C,EAC3C,QAA2B;QAE3B,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,cAAc,EAAE,CAAC;YAClB,OAAO;QACX,CAAC;QAED,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,cAAc,CAAC;QACpC,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7D,IAAI,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QACxE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACjD,IAAI,OAAO,EAAE,CAAC;gBACV,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC;YACvB,CAAC;QACL,CAAC;QAED,2IAA2I;QAC3I,8DAA8D;QAC9D,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAChD,OAAO;QACX,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,gDAA0B,CAAC,EAAE,CAAC;YAC3D,yBAAyB;YACzB,OAAO;QACX,CAAC;QAED,OAAO,IAAI,gDAA0B,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5E,CAAC;IAEO,kBAAkB,CACtB,OAAe,EACf,MAAc,EACd,MAA4C;QAE5C,MAAM,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACrD,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACrB,OAAO;QACX,CAAC;QAED,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,iBAAiB,CAAC;QACvC,MAAM,WAAW,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAE3D,OAAO,IAAI,mDAA6B,CAAC,QAAQ,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IAC1E,CAAC;IAED;;;;;OAKG;IACO,iBAAiB,CACvB,OAAe,EACf,MAAc,EACd,MAA4C;QAE5C,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACnD,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACpB,OAAO;QACX,CAAC;QAED,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,GAAG,gBAAgB,CAAC;QACpD,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,WAAW,CAAC,EAAE,CAAC;YACxC,oFAAoF;YACpF,+EAA+E;YAC/E,iFAAiF;YACjF,OAAO;QACX,CAAC;QACD,IAAI,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC;QACpC,IAAI,WAA+B,CAAC;QAEpC,8FAA8F;QAC9F,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,eAAe,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC;QAC1E,MAAM,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QACnF,MAAM,OAAO,GAAG,iBAAiB,IAAI,OAAO,CAAC;QAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,IAAI,EAAE,CAAC;YACP,WAAW,GAAG,IAAI,CAAC;YACnB,uFAAuF;YACvF,uFAAuF;YACvF,uFAAuF;YACvF,0FAA0F;YAC1F,UAAU,GAAG,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC;QAE9D,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,WAAW,IAAI,WAAW,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;QAChF,OAAO,IAAI,mDAA6B,CAAC,YAAY,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IAClF,CAAC;IAEO,qBAAqB,CAAC,OAAe,EAAE,WAAmB,EAAE,SAAiB;QACjF,cAAc,CAAC,SAAS,GAAG,WAAW,CAAC;QACvC,IAAI,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,KAAK,IAAI,KAAK,CAAC,KAAK,GAAG,SAAS,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,OAAO,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,0CAAoB,CAAC,CAAC;YAChE,CAAC;YACD,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACO,kBAAkB,CAAC,WAAmB;QAC5C,OAAO,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IAC1D,CAAC;IAEO,kBAAkB,CAAC,OAAe,EAAE,MAAc;QACtD,yDAAyD;QACzD,MAAM,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/F,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACrB,OAAO;QACX,CAAC;QAED,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,iBAAiB,CAAC;QACxC,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,IAAA,gCAAsB,EAAC,KAAK,CAAC,CAAC;QAEvD,MAAM,gBAAgB,GAAG,IAAI,CAAC,sBAAsB,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QACrE,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACpB,OAAO;QACX,CAAC;QAED,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAChE,OAAO,IAAI,mDAA6B,CAAC,aAAa,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IACxF,CAAC;CACJ,CAAA;AAnTY,sDAAqB;AAGX;IADlB,IAAA,kBAAM,EAAC,uBAAa,CAAC;;4DAC0B;gCAHvC,qBAAqB;IADjC,IAAA,sBAAU,GAAE;IAOJ,mBAAA,IAAA,kBAAM,EAAC,qCAAgB,CAAC,CAAA;IACxB,mBAAA,IAAA,kBAAM,EAAC,2BAAiB,CAAC,CAAA;IACzB,mBAAA,IAAA,kBAAM,EAAC,gCAAsB,CAAC,CAAA;IAC9B,mBAAA,IAAA,kBAAM,EAAC,cAAO,CAAC,CAAA;;GATX,qBAAqB,CAmTjC"}
|
|
@@ -25,11 +25,21 @@ const core_1 = require("@theia/core");
|
|
|
25
25
|
const parsed_chat_request_1 = require("./parsed-chat-request");
|
|
26
26
|
const agent_delegation_tool_1 = require("../browser/agent-delegation-tool");
|
|
27
27
|
describe('ChatRequestParserImpl', () => {
|
|
28
|
+
/** Command names the stubbed `PromptService` knows about. Anything else is not a command. */
|
|
29
|
+
const KNOWN_COMMANDS = ['hello', 'explain', 'compare', 'cmd', 'summarize', 'skill-one', 'skill-two'];
|
|
30
|
+
/** Prompt fragments that are not marked as commands, but can still be invoked by their id. */
|
|
31
|
+
const KNOWN_FRAGMENT_IDS = ['coder-system'];
|
|
32
|
+
const promptService = {
|
|
33
|
+
isKnownCommand: (name) => KNOWN_COMMANDS.includes(name) || KNOWN_FRAGMENT_IDS.includes(name),
|
|
34
|
+
getCommands: () => KNOWN_COMMANDS.map(name => ({ id: `command-${name}`, template: '', isCommand: true, commandName: name }))
|
|
35
|
+
};
|
|
28
36
|
const chatAgentService = sinon.createStubInstance(chat_agent_service_1.ChatAgentServiceImpl);
|
|
29
37
|
const variableService = sinon.createStubInstance(ai_core_1.DefaultAIVariableService);
|
|
30
38
|
const toolInvocationRegistry = sinon.createStubInstance(ai_core_1.ToolInvocationRegistryImpl);
|
|
31
39
|
const logger = sinon.createStubInstance(core_1.Logger);
|
|
32
40
|
const parser = new chat_request_parser_1.ChatRequestParserImpl(chatAgentService, variableService, toolInvocationRegistry, logger);
|
|
41
|
+
// The parser injects the PromptService as a property, so it has to be assigned manually here.
|
|
42
|
+
parser.promptService = promptService;
|
|
33
43
|
beforeEach(() => {
|
|
34
44
|
// Reset our stubs before each test
|
|
35
45
|
sinon.reset();
|
|
@@ -235,6 +245,58 @@ describe('ChatRequestParserImpl', () => {
|
|
|
235
245
|
const varPart = result.parts[0];
|
|
236
246
|
(0, chai_1.expect)(varPart.variableArg).to.equal('cmd|"arg with \\"quote\\"" other');
|
|
237
247
|
});
|
|
248
|
+
it('parses multiple commands in one message', async () => {
|
|
249
|
+
const req = {
|
|
250
|
+
text: '/skill-one /skill-two'
|
|
251
|
+
};
|
|
252
|
+
const context = { variables: [] };
|
|
253
|
+
const result = await parser.parseChatRequest(req, chat_agents_1.ChatAgentLocation.Panel, context);
|
|
254
|
+
(0, chai_1.expect)(result.parts.length).to.equal(3);
|
|
255
|
+
const firstCommand = result.parts[0];
|
|
256
|
+
const separator = result.parts[1];
|
|
257
|
+
const secondCommand = result.parts[2];
|
|
258
|
+
(0, chai_1.expect)(firstCommand.variableName).to.equal('prompt');
|
|
259
|
+
(0, chai_1.expect)(firstCommand.variableArg).to.equal('skill-one');
|
|
260
|
+
(0, chai_1.expect)(separator.text).to.equal(' ');
|
|
261
|
+
(0, chai_1.expect)(secondCommand.variableName).to.equal('prompt');
|
|
262
|
+
(0, chai_1.expect)(secondCommand.variableArg).to.equal('skill-two');
|
|
263
|
+
});
|
|
264
|
+
it('inserts a separator between two argument-taking commands', async () => {
|
|
265
|
+
const req = {
|
|
266
|
+
text: '/summarize foo /hello bar'
|
|
267
|
+
};
|
|
268
|
+
const context = { variables: [] };
|
|
269
|
+
const result = await parser.parseChatRequest(req, chat_agents_1.ChatAgentLocation.Panel, context);
|
|
270
|
+
(0, chai_1.expect)(result.parts.length).to.equal(3);
|
|
271
|
+
const firstCommand = result.parts[0];
|
|
272
|
+
const separator = result.parts[1];
|
|
273
|
+
const secondCommand = result.parts[2];
|
|
274
|
+
(0, chai_1.expect)(firstCommand.variableArg).to.equal('summarize|foo');
|
|
275
|
+
(0, chai_1.expect)(separator.kind).to.equal('text');
|
|
276
|
+
(0, chai_1.expect)(separator.text).to.equal(' ');
|
|
277
|
+
(0, chai_1.expect)(secondCommand.variableArg).to.equal('hello|bar');
|
|
278
|
+
});
|
|
279
|
+
it('keeps path-like slash arguments as command arguments', async () => {
|
|
280
|
+
const req = {
|
|
281
|
+
text: '/explain /path/to/file'
|
|
282
|
+
};
|
|
283
|
+
const context = { variables: [] };
|
|
284
|
+
const result = await parser.parseChatRequest(req, chat_agents_1.ChatAgentLocation.Panel, context);
|
|
285
|
+
(0, chai_1.expect)(result.parts.length).to.equal(1);
|
|
286
|
+
const varPart = result.parts[0];
|
|
287
|
+
(0, chai_1.expect)(varPart.variableName).to.equal('prompt');
|
|
288
|
+
(0, chai_1.expect)(varPart.variableArg).to.equal('explain|/path/to/file');
|
|
289
|
+
});
|
|
290
|
+
it('does not treat path segments as commands', async () => {
|
|
291
|
+
const req = {
|
|
292
|
+
text: 'please look at /home/user/notes.txt and fix the bug'
|
|
293
|
+
};
|
|
294
|
+
const context = { variables: [] };
|
|
295
|
+
const result = await parser.parseChatRequest(req, chat_agents_1.ChatAgentLocation.Panel, context);
|
|
296
|
+
(0, chai_1.expect)(result.parts.length).to.equal(1);
|
|
297
|
+
(0, chai_1.expect)(result.parts[0].kind).to.equal('text');
|
|
298
|
+
(0, chai_1.expect)(result.parts[0].text).to.equal(req.text);
|
|
299
|
+
});
|
|
238
300
|
it('treats the first @agent mention as the selector and does not allow later mentions to override it', async () => {
|
|
239
301
|
const createAgent = (id) => ({
|
|
240
302
|
id,
|
|
@@ -388,6 +450,277 @@ describe('ChatRequestParserImpl', () => {
|
|
|
388
450
|
(0, chai_1.expect)(result.deferredToolIds?.has('eagerTool')).to.be.false;
|
|
389
451
|
});
|
|
390
452
|
});
|
|
453
|
+
describe('slash command disambiguation', () => {
|
|
454
|
+
const parse = (text) => parser.parseChatRequest({ text }, chat_agents_1.ChatAgentLocation.Panel, { variables: [] });
|
|
455
|
+
/** Every character of the input has to be covered by exactly one part, in order and without gaps. */
|
|
456
|
+
const expectFullCoverage = (parts, text) => {
|
|
457
|
+
let expectedStart = 0;
|
|
458
|
+
for (const part of parts) {
|
|
459
|
+
(0, chai_1.expect)(part.range.start, `part starting at ${part.range.start} does not continue at ${expectedStart}`).to.equal(expectedStart);
|
|
460
|
+
expectedStart = part.range.endExclusive;
|
|
461
|
+
}
|
|
462
|
+
(0, chai_1.expect)(expectedStart, 'parts do not cover the whole message').to.equal(text.length);
|
|
463
|
+
};
|
|
464
|
+
const expectPlainText = async (text) => {
|
|
465
|
+
const result = await parse(text);
|
|
466
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind), `expected only text parts for ${JSON.stringify(text)}`).to.deep.equal(['text']);
|
|
467
|
+
(0, chai_1.expect)(result.parts[0].text).to.equal(text);
|
|
468
|
+
expectFullCoverage(result.parts, text);
|
|
469
|
+
};
|
|
470
|
+
describe('unknown commands stay plain text', () => {
|
|
471
|
+
const unknownCommandInputs = [
|
|
472
|
+
'please look at /home/user/notes.txt and fix the bug',
|
|
473
|
+
'/home/user/notes.txt is broken',
|
|
474
|
+
'read /usr/local/bin/theia',
|
|
475
|
+
'the file is at /etc/hosts',
|
|
476
|
+
'compare /tmp/a.txt with /tmp/b.txt',
|
|
477
|
+
'run cd /home && ls',
|
|
478
|
+
'see /usr/lib/node/foo.js:12 for the stack trace',
|
|
479
|
+
'what does the option --foo /bar do?',
|
|
480
|
+
'/does-not-exist do something',
|
|
481
|
+
'/tmp',
|
|
482
|
+
'move it to /tmp',
|
|
483
|
+
'the separator is / on Unix'
|
|
484
|
+
];
|
|
485
|
+
unknownCommandInputs.forEach(text => {
|
|
486
|
+
it(`keeps ${JSON.stringify(text)} as plain text`, () => expectPlainText(text));
|
|
487
|
+
});
|
|
488
|
+
it('does not drop any user text when a path follows a known command name prefix', async () => {
|
|
489
|
+
// `/summarizes` is not a known command, even though `/summarize` is.
|
|
490
|
+
await expectPlainText('/summarizes the file');
|
|
491
|
+
});
|
|
492
|
+
it('does not treat a known command name as a command when it is a path segment', async () => {
|
|
493
|
+
// `summarize` is known, but `/summarize/foo` is a path, not a command invocation.
|
|
494
|
+
await expectPlainText('/summarize/foo is a path');
|
|
495
|
+
});
|
|
496
|
+
it('does not treat a known command name followed by punctuation as a command', async () => {
|
|
497
|
+
await expectPlainText('did you mean /summarize?');
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
describe('slashes that are not command leaders', () => {
|
|
501
|
+
const nonLeaderInputs = [
|
|
502
|
+
'A: 10/20 and B: 30/40',
|
|
503
|
+
'use and/or here',
|
|
504
|
+
'2026/08/04 is the date',
|
|
505
|
+
'see https://example.com/foo/bar for details',
|
|
506
|
+
'the regex is a\\/b'
|
|
507
|
+
];
|
|
508
|
+
nonLeaderInputs.forEach(text => {
|
|
509
|
+
it(`keeps ${JSON.stringify(text)} as plain text`, () => expectPlainText(text));
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
describe('known commands still parse', () => {
|
|
513
|
+
it('parses a known command without arguments', async () => {
|
|
514
|
+
const text = '/summarize';
|
|
515
|
+
const result = await parse(text);
|
|
516
|
+
(0, chai_1.expect)(result.parts.length).to.equal(1);
|
|
517
|
+
const command = result.parts[0];
|
|
518
|
+
(0, chai_1.expect)(command.variableName).to.equal('prompt');
|
|
519
|
+
(0, chai_1.expect)(command.variableArg).to.equal('summarize');
|
|
520
|
+
expectFullCoverage(result.parts, text);
|
|
521
|
+
});
|
|
522
|
+
it('parses a known command with arguments', async () => {
|
|
523
|
+
const text = '/summarize foo bar';
|
|
524
|
+
const result = await parse(text);
|
|
525
|
+
(0, chai_1.expect)(result.parts.length).to.equal(1);
|
|
526
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize|foo bar');
|
|
527
|
+
expectFullCoverage(result.parts, text);
|
|
528
|
+
});
|
|
529
|
+
it('keeps a path as the argument of a known command', async () => {
|
|
530
|
+
const text = '/summarize /home/user/notes.txt';
|
|
531
|
+
const result = await parse(text);
|
|
532
|
+
(0, chai_1.expect)(result.parts.length).to.equal(1);
|
|
533
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize|/home/user/notes.txt');
|
|
534
|
+
expectFullCoverage(result.parts, text);
|
|
535
|
+
});
|
|
536
|
+
it('keeps an unknown slash token inside the arguments of a known command', async () => {
|
|
537
|
+
const text = '/summarize foo /unknown bar';
|
|
538
|
+
const result = await parse(text);
|
|
539
|
+
(0, chai_1.expect)(result.parts.length).to.equal(1);
|
|
540
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize|foo /unknown bar');
|
|
541
|
+
expectFullCoverage(result.parts, text);
|
|
542
|
+
});
|
|
543
|
+
it('parses a known command in the middle of a message', async () => {
|
|
544
|
+
const text = 'please /summarize this';
|
|
545
|
+
const result = await parse(text);
|
|
546
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['text', 'var']);
|
|
547
|
+
(0, chai_1.expect)(result.parts[0].text).to.equal('please ');
|
|
548
|
+
(0, chai_1.expect)(result.parts[1].variableArg).to.equal('summarize|this');
|
|
549
|
+
expectFullCoverage(result.parts, text);
|
|
550
|
+
});
|
|
551
|
+
it('parses two adjacent known commands', async () => {
|
|
552
|
+
const text = '/skill-one /skill-two';
|
|
553
|
+
const result = await parse(text);
|
|
554
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var']);
|
|
555
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('skill-one');
|
|
556
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal(' ');
|
|
557
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('skill-two');
|
|
558
|
+
expectFullCoverage(result.parts, text);
|
|
559
|
+
});
|
|
560
|
+
it('separates two argument-taking known commands', async () => {
|
|
561
|
+
const text = '/summarize foo /explain bar';
|
|
562
|
+
const result = await parse(text);
|
|
563
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var']);
|
|
564
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize|foo');
|
|
565
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal(' ');
|
|
566
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('explain|bar');
|
|
567
|
+
expectFullCoverage(result.parts, text);
|
|
568
|
+
});
|
|
569
|
+
it('parses the same command twice, each with its own argument', async () => {
|
|
570
|
+
const text = '/hello Klaus /hello Maria';
|
|
571
|
+
const result = await parse(text);
|
|
572
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var']);
|
|
573
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('hello|Klaus');
|
|
574
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal(' ');
|
|
575
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('hello|Maria');
|
|
576
|
+
expectFullCoverage(result.parts, text);
|
|
577
|
+
});
|
|
578
|
+
it('parses the same command three times', async () => {
|
|
579
|
+
const text = '/hello Klaus /hello Maria /hello Bob';
|
|
580
|
+
const result = await parse(text);
|
|
581
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var', 'text', 'var']);
|
|
582
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('hello|Klaus');
|
|
583
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('hello|Maria');
|
|
584
|
+
(0, chai_1.expect)(result.parts[4].variableArg).to.equal('hello|Bob');
|
|
585
|
+
expectFullCoverage(result.parts, text);
|
|
586
|
+
});
|
|
587
|
+
it('parses the same command twice without arguments', async () => {
|
|
588
|
+
const text = '/hello /hello';
|
|
589
|
+
const result = await parse(text);
|
|
590
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var']);
|
|
591
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('hello');
|
|
592
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal(' ');
|
|
593
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('hello');
|
|
594
|
+
expectFullCoverage(result.parts, text);
|
|
595
|
+
});
|
|
596
|
+
it('accepts a prompt fragment id as a command', async () => {
|
|
597
|
+
const text = '/coder-system';
|
|
598
|
+
const result = await parse(text);
|
|
599
|
+
(0, chai_1.expect)(result.parts.length).to.equal(1);
|
|
600
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('coder-system');
|
|
601
|
+
});
|
|
602
|
+
it('keeps trailing whitespace out of the command part', async () => {
|
|
603
|
+
const text = '/summarize ';
|
|
604
|
+
const result = await parse(text);
|
|
605
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text']);
|
|
606
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize');
|
|
607
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal(' ');
|
|
608
|
+
expectFullCoverage(result.parts, text);
|
|
609
|
+
});
|
|
610
|
+
it('trims whitespace around arguments', async () => {
|
|
611
|
+
const text = '/summarize \t foo \t ';
|
|
612
|
+
const result = await parse(text);
|
|
613
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize|foo');
|
|
614
|
+
expectFullCoverage(result.parts, text);
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
describe('arguments do not span multiple lines', () => {
|
|
618
|
+
it('does not consume the following line for a command without arguments', async () => {
|
|
619
|
+
const text = '/summarize\nsecond line';
|
|
620
|
+
const result = await parse(text);
|
|
621
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text']);
|
|
622
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize');
|
|
623
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal('\nsecond line');
|
|
624
|
+
expectFullCoverage(result.parts, text);
|
|
625
|
+
});
|
|
626
|
+
it('does not consume the following line for a command with arguments', async () => {
|
|
627
|
+
const text = '/summarize foo\nsecond line\nthird line';
|
|
628
|
+
const result = await parse(text);
|
|
629
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text']);
|
|
630
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize|foo');
|
|
631
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal('\nsecond line\nthird line');
|
|
632
|
+
expectFullCoverage(result.parts, text);
|
|
633
|
+
});
|
|
634
|
+
it('handles CRLF line endings', async () => {
|
|
635
|
+
const text = '/summarize foo\r\nsecond line';
|
|
636
|
+
const result = await parse(text);
|
|
637
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text']);
|
|
638
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize|foo');
|
|
639
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal('\r\nsecond line');
|
|
640
|
+
expectFullCoverage(result.parts, text);
|
|
641
|
+
});
|
|
642
|
+
it('parses a command on a later line', async () => {
|
|
643
|
+
const text = 'first line\n/summarize foo\nthird line';
|
|
644
|
+
const result = await parse(text);
|
|
645
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['text', 'var', 'text']);
|
|
646
|
+
(0, chai_1.expect)(result.parts[0].text).to.equal('first line\n');
|
|
647
|
+
(0, chai_1.expect)(result.parts[1].variableArg).to.equal('summarize|foo');
|
|
648
|
+
(0, chai_1.expect)(result.parts[2].text).to.equal('\nthird line');
|
|
649
|
+
expectFullCoverage(result.parts, text);
|
|
650
|
+
});
|
|
651
|
+
it('parses one command per line', async () => {
|
|
652
|
+
const text = '/summarize foo\n/explain bar';
|
|
653
|
+
const result = await parse(text);
|
|
654
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var']);
|
|
655
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('summarize|foo');
|
|
656
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal('\n');
|
|
657
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('explain|bar');
|
|
658
|
+
expectFullCoverage(result.parts, text);
|
|
659
|
+
});
|
|
660
|
+
it('parses the same command on consecutive lines', async () => {
|
|
661
|
+
const text = '/hello Klaus\n/hello Maria';
|
|
662
|
+
const result = await parse(text);
|
|
663
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var']);
|
|
664
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('hello|Klaus');
|
|
665
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal('\n');
|
|
666
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('hello|Maria');
|
|
667
|
+
expectFullCoverage(result.parts, text);
|
|
668
|
+
});
|
|
669
|
+
it('keeps a blank line between two commands', async () => {
|
|
670
|
+
const text = '/hello Klaus\n\n/hello Maria';
|
|
671
|
+
const result = await parse(text);
|
|
672
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var']);
|
|
673
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('hello|Klaus');
|
|
674
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal('\n\n');
|
|
675
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('hello|Maria');
|
|
676
|
+
expectFullCoverage(result.parts, text);
|
|
677
|
+
});
|
|
678
|
+
it('mixes a line break with a repetition on the same line', async () => {
|
|
679
|
+
const text = '/hello Klaus\n/hello Maria and /hello Bob';
|
|
680
|
+
const result = await parse(text);
|
|
681
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text', 'var', 'text', 'var']);
|
|
682
|
+
(0, chai_1.expect)(result.parts[0].variableArg).to.equal('hello|Klaus');
|
|
683
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal('\n');
|
|
684
|
+
(0, chai_1.expect)(result.parts[2].variableArg).to.equal('hello|Maria and');
|
|
685
|
+
(0, chai_1.expect)(result.parts[3].text).to.equal(' ');
|
|
686
|
+
(0, chai_1.expect)(result.parts[4].variableArg).to.equal('hello|Bob');
|
|
687
|
+
expectFullCoverage(result.parts, text);
|
|
688
|
+
});
|
|
689
|
+
it('keeps a multi-line paste containing paths untouched', async () => {
|
|
690
|
+
await expectPlainText('here is a stack trace:\n at /usr/lib/node/foo.js:12\nplease fix it');
|
|
691
|
+
});
|
|
692
|
+
});
|
|
693
|
+
describe('interaction with other request parts', () => {
|
|
694
|
+
it('does not turn a path into a command when it follows a variable', async () => {
|
|
695
|
+
const text = '#file:/path/to/file.ext look at /home/user/notes.txt';
|
|
696
|
+
const result = await parse(text);
|
|
697
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['var', 'text']);
|
|
698
|
+
(0, chai_1.expect)(result.parts[0].variableName).to.equal('file');
|
|
699
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal(' look at /home/user/notes.txt');
|
|
700
|
+
expectFullCoverage(result.parts, text);
|
|
701
|
+
});
|
|
702
|
+
it('does not turn a path into a command when it follows an agent mention', async () => {
|
|
703
|
+
chatAgentService.getAgents.returns([{
|
|
704
|
+
id: 'agentA',
|
|
705
|
+
name: 'agentA',
|
|
706
|
+
description: '',
|
|
707
|
+
tags: [],
|
|
708
|
+
variables: [],
|
|
709
|
+
prompts: [],
|
|
710
|
+
agentSpecificVariables: [],
|
|
711
|
+
functions: [],
|
|
712
|
+
languageModelRequirements: [],
|
|
713
|
+
locations: [chat_agents_1.ChatAgentLocation.Panel],
|
|
714
|
+
invoke: async () => undefined
|
|
715
|
+
}]);
|
|
716
|
+
const text = '@agentA please read /etc/hosts';
|
|
717
|
+
const result = await parse(text);
|
|
718
|
+
(0, chai_1.expect)(result.parts.map(p => p.kind)).to.deep.equal(['agent', 'text']);
|
|
719
|
+
(0, chai_1.expect)(result.parts[1].text).to.equal(' please read /etc/hosts');
|
|
720
|
+
expectFullCoverage(result.parts, text);
|
|
721
|
+
});
|
|
722
|
+
});
|
|
723
|
+
});
|
|
391
724
|
describe('parsed chat request part kind assignments', () => {
|
|
392
725
|
it('ParsedChatRequestTextPart has kind assigned at runtime', () => {
|
|
393
726
|
const part = new parsed_chat_request_1.ParsedChatRequestTextPart({ start: 0, endExclusive: 5 }, 'hello');
|