Skip to content

Commit

Permalink
Merge pull request #87 from CommandDash/rel-0.1.2
Browse files Browse the repository at this point in the history
Rel 0.1.2
  • Loading branch information
samyakkkk authored Jun 14, 2024
2 parents 34b3789 + adc2cfb commit 8070ce0
Show file tree
Hide file tree
Showing 23 changed files with 928 additions and 224 deletions.
4 changes: 2 additions & 2 deletions commanddash/lib/runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class VersionCommand extends Command {
@override
void run() {
/// It is not possible to fetch version from pubspec.yaml hence assigning manually
print('0.1.1');
print('0.1.2');
}
}

Expand All @@ -49,6 +49,6 @@ class MinimumClientVersionCommand extends Command {

@override
void run() {
print('0.4.0');
print('0.4.4');
}
}
147 changes: 76 additions & 71 deletions commanddash/lib/steps/chat/chat_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,82 +84,87 @@ class ChatStep extends Step {
List<WorkspaceFile> includedInPrompt = [];
final Map<String, int> nestedCodes = {};

void appendNestedCodeCount(String filePath, {int priority = 1}) {
nestedCodes[filePath] = (nestedCodes[filePath] ?? 0) + priority;
}
// This function is commented out because it is not used as contextual code is not added for now.
// void appendNestedCodeCount(String filePath, {int priority = 1}) {
// nestedCodes[filePath] = (nestedCodes[filePath] ?? 0) + priority;
// }

void markIncludedInPrompt(
{required String path, required List<Range> ranges}) {
final existingFileIndex =
includedInPrompt.indexWhere((file) => file.path == path);
if (existingFileIndex != -1) {
includedInPrompt[existingFileIndex].selectedRanges.addAll(ranges);
} else {
includedInPrompt
.add(WorkspaceFile.fromPath(path, selectedRanges: ranges));
}
}
// void markIncludedInPrompt(
// {required String path, required List<Range> ranges}) {
// final existingFileIndex =
// includedInPrompt.indexWhere((file) => file.path == path);
// if (existingFileIndex != -1) {
// includedInPrompt[existingFileIndex].selectedRanges.addAll(ranges);
// } else {
// includedInPrompt
// .add(WorkspaceFile.fromPath(path, selectedRanges: ranges));
// }
// }

for (CodeInput code in codeInputs) {
/// add the code file itself as context
appendNestedCodeCount(code.filePath, priority: 10);
// Skipping adding contextual code for now due to the lack of a consistent way to retrieve document definitions for all languages.
// This feature may be added in the future when a reliable method becomes available.
// Commented out the code below that adds contextual code.
// for (CodeInput code in codeInputs) {
// /// add the code file itself as context
// appendNestedCodeCount(code.filePath, priority: 10);

final data = await taskAssist.processStep(
kind: "context",
args: {
"filePath": code.filePath,
"range": code.range.toJson(),
},
timeoutKind: TimeoutKind.stretched,
);
final context = data['context'];
if (context != null) {
final listOfContext = List<Map<String, dynamic>>.from(context);
for (final nestedCode in listOfContext) {
final filePath = nestedCode['filePath'];
appendNestedCodeCount(filePath);
}
}
}
// final data = await taskAssist.processStep(
// kind: "context",
// args: {
// "filePath": code.filePath,
// "range": code.range.toJson(),
// },
// timeoutKind: TimeoutKind.stretched,
// );
// final context = data['context'];
// if (context != null) {
// final listOfContext = List<Map<String, dynamic>>.from(context);
// for (final nestedCode in listOfContext) {
// final filePath = nestedCode['filePath'];
// appendNestedCodeCount(filePath);
// }
// }
// }
// nestedCode sorted by frequency
final sortedNestedCode = nestedCodes.entries.toList()
..sort(((a, b) {
return b.value.compareTo(a.value);
}));
String contextualCodePrefix =
"[CONTEXTUAL CODE FOR YOUR INFORMATION FROM USER PROJECT]\n\n";
String contextualCode = "";
// final sortedNestedCode = nestedCodes.entries.toList()
// ..sort(((a, b) {
// return b.value.compareTo(a.value);
// }));
// String contextualCodePrefix =
// "[CONTEXTUAL CODE FOR YOUR INFORMATION FROM USER PROJECT]\n\n";
// String contextualCode = "";

///TODO: Figure out a way to attach the most relevant part of the file if the full file is extremely long
for (final nestedFilePath in sortedNestedCode.map((e) => e.key)) {
final includedInPromptIndex = includedInPrompt
.indexWhere((element) => element.path == nestedFilePath);
if (includedInPromptIndex != -1) {
final content =
includedInPrompt[includedInPromptIndex].surroundingContent;
if (content != null) {
if (availableToken - content.length > 0) {
contextualCode =
'$contextualCode$nestedFilePath\n```$content```\n\n';
availableToken -= content.length;
}
}
continue;
}
final content = (await File(nestedFilePath).readAsString())
.replaceAll(RegExp(r"[\n\s]+"), "");
if (content.length > 9500) {
continue; // Don't include extremely large nested code files.
}
if (availableToken - content.length < 0) continue;
contextualCode = '$contextualCode$nestedFilePath\n```$content```\n\n';
availableToken -= content.length;
}
if (contextualCode.isNotEmpty) {
contextualCode =
'$contextualCodePrefix$contextualCode\n\n[END OF CONTEXTUAL CODE.]\n\n';
prompt = '$contextualCode$prompt';
}
// ///TODO: Figure out a way to attach the most relevant part of the file if the full file is extremely long
// for (final nestedFilePath in sortedNestedCode.map((e) => e.key)) {
// final includedInPromptIndex = includedInPrompt
// .indexWhere((element) => element.path == nestedFilePath);
// if (includedInPromptIndex != -1) {
// final content =
// includedInPrompt[includedInPromptIndex].surroundingContent;
// if (content != null) {
// if (availableToken - content.length > 0) {
// contextualCode =
// '$contextualCode$nestedFilePath\n```$content```\n\n';
// availableToken -= content.length;
// }
// }
// continue;
// }
// final content = (await File(nestedFilePath).readAsString())
// .replaceAll(RegExp(r"[\n\s]+"), "");
// if (content.length > 9500) {
// continue; // Don't include extremely large nested code files.
// }
// if (availableToken - content.length < 0) continue;
// contextualCode = '$contextualCode$nestedFilePath\n```$content```\n\n';
// availableToken -= content.length;
// }
// if (contextualCode.isNotEmpty) {
// contextualCode =
// '$contextualCodePrefix$contextualCode\n\n[END OF CONTEXTUAL CODE.]\n\n';
// prompt = '$contextualCode$prompt';
// }
print(prompt);
var filesInvolved = Set<String>.from(
includedInPrompt.map((e) => e.path).toList() +
nestedCodes.keys.toList())
Expand Down
128 changes: 64 additions & 64 deletions commanddash/lib/steps/prompt_query/prompt_query_step.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,35 +99,35 @@ class PromptQueryStep extends Step {

for (String id in usedIds) {
if (inputs.containsKey(id)) {
switch (inputs[id].runtimeType) {
case CodeInput:
final code = inputs[id] as CodeInput;
markIncludedInPrompt(
path: (inputs[id] as CodeInput).filePath,
ranges: [(inputs[id] as CodeInput).range]);
if ((inputs[id] as CodeInput).includeContextualCode) {
/// add the code file itself as context
appendNestedCodeCount(code.filePath, priority: 10);

final data = await taskAssist.processStep(
kind: "context",
args: {
"filePath": code.filePath,
"range": code.range.toJson(),
},
timeoutKind: TimeoutKind.stretched,
);
final context = data['context'];
if (context != null) {
final listOfContext = List<Map<String, dynamic>>.from(context);
for (final nestedCode in listOfContext) {
final filePath = nestedCode['filePath'];
appendNestedCodeCount(filePath);
}
}
}
break;
}
// switch (inputs[id].runtimeType) {
// case CodeInput:
// // final code = inputs[id] as CodeInput;
// // markIncludedInPrompt(
// // path: (inputs[id] as CodeInput).filePath,
// // ranges: [(inputs[id] as CodeInput).range]);
// // if ((inputs[id] as CodeInput).includeContextualCode) {
// // /// add the code file itself as context
// // appendNestedCodeCount(code.filePath, priority: 10);

// // final data = await taskAssist.processStep(
// // kind: "context",
// // args: {
// // "filePath": code.filePath,
// // "range": code.range.toJson(),
// // },
// // timeoutKind: TimeoutKind.stretched,
// // );
// // final context = data['context'];
// // if (context != null) {
// // final listOfContext = List<Map<String, dynamic>>.from(context);
// // for (final nestedCode in listOfContext) {
// // final filePath = nestedCode['filePath'];
// // appendNestedCodeCount(filePath);
// // }
// // }
// // }
// // break;
// }
} else if (outputsUntilNow.containsKey(id)) {
switch (outputsUntilNow[id].runtimeType) {
case MultiCodeOutput:
Expand All @@ -143,41 +143,41 @@ class PromptQueryStep extends Step {
}
}

// nestedCode sorted by frequency
final sortedNestedCode = nestedCodes.entries.toList()
..sort(((a, b) {
return b.value.compareTo(a.value);
}));
String contextualCode =
"[CONTEXTUAL CODE FOR YOUR INFORMATION FROM USER PROJECT]\n\n";

///TODO: Figure out a way to attach the most relevant part of the file if the full file is extremely long
for (final nestedFilePath in sortedNestedCode.map((e) => e.key)) {
final includedInPromptIndex = includedInPrompt
.indexWhere((element) => element.path == nestedFilePath);
if (includedInPromptIndex != -1) {
final content =
includedInPrompt[includedInPromptIndex].surroundingContent;
if (content != null) {
if (availableToken - content.length > 0) {
contextualCode =
'$contextualCode$nestedFilePath\n```$content```\n\n';
availableToken -= content.length;
}
}
continue;
}
final content = (await File(nestedFilePath).readAsString())
.replaceAll(RegExp(r"[\n\s]+"), "");
if (content.length > 9500) {
continue; // Don't include extremely large nested code files.
}
if (availableToken - content.length < 0) continue;
contextualCode = '$contextualCode$nestedFilePath\n```$content```\n\n';
availableToken -= content.length;
}
contextualCode = '$contextualCode\n\n[END OF CONTEXTUAL CODE.]\n\n';
prompt = '$contextualCode$prompt';
// // nestedCode sorted by frequency
// final sortedNestedCode = nestedCodes.entries.toList()
// ..sort(((a, b) {
// return b.value.compareTo(a.value);
// }));
// String contextualCode =
// "[CONTEXTUAL CODE FOR YOUR INFORMATION FROM USER PROJECT]\n\n";

// ///TODO: Figure out a way to attach the most relevant part of the file if the full file is extremely long
// for (final nestedFilePath in sortedNestedCode.map((e) => e.key)) {
// final includedInPromptIndex = includedInPrompt
// .indexWhere((element) => element.path == nestedFilePath);
// if (includedInPromptIndex != -1) {
// final content =
// includedInPrompt[includedInPromptIndex].surroundingContent;
// if (content != null) {
// if (availableToken - content.length > 0) {
// contextualCode =
// '$contextualCode$nestedFilePath\n```$content```\n\n';
// availableToken -= content.length;
// }
// }
// continue;
// }
// final content = (await File(nestedFilePath).readAsString())
// .replaceAll(RegExp(r"[\n\s]+"), "");
// if (content.length > 9500) {
// continue; // Don't include extremely large nested code files.
// }
// if (availableToken - content.length < 0) continue;
// contextualCode = '$contextualCode$nestedFilePath\n```$content```\n\n';
// availableToken -= content.length;
// }
// contextualCode = '$contextualCode\n\n[END OF CONTEXTUAL CODE.]\n\n';
// prompt = '$contextualCode$prompt';

var filesInvolved = Set<String>.from(
includedInPrompt.map((e) => e.path).toList() +
Expand Down
6 changes: 6 additions & 0 deletions dash_agent/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.3.0

* **Github Data Object Support**: Added support to extract Github repo data conviniently. You can use `WebDataObject.fromGithub` for indexing a specific repo code and issues now.
* **Commandless Mode Support**: Added Commandless mode which is active by default when an agent is activated. Now you can interact with agent more naturally by chatting.
* **Metadata**: Added support to provide agent avatar and human readable display name. As an agent creator you can also set tags for agents that will help better visibilty for agents in the agent marketplace as well as devs to understand for what purposes or framework the agent can be used.

## 0.2.1

* **Updated README**: Fixed broken images in README
Expand Down
32 changes: 25 additions & 7 deletions dash_agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,41 @@ Sample example of `AgentConfiguration`:
```dart
class MyAgent extends AgentConfiguration {
final docsSource = DocsDataSource();
final blogsSource = BlogsDataSource();
@override
List<DataSource> get registeredDataSources => [docsSource];
List<DataSource> get registerDataSources => [docsSource, blogsSource];
@override
List<Command> get registerSupportedCommands =>
[AskCommand(docsSource: docsSource)];
@override
Metadata get metadata => Metadata(
name: 'My Agent',
avatarProfile: 'assets/images/agent_avatar.png',
tags: ['flutter', 'dart'],
);
@override
String get registerSystemPrompt => '''You are a Flutter expert who answers user queries related to the framework.
Note:
1. If the references don't address the question, state that "I couldn't fetch your answer from the doc sources, but I'll try to answer from my own knowledge".
2. Be truthful, complete and detailed with your responses and include code snippets wherever required''';
}
```

The above AgentConfiguration registers your data sources and supported commands.
The above AgentConfiguration registers your data sources, supported commands, metadata, and system prompt.

- `DataSource`: Data sources enable you to provide any form of data that your agent might need to perform its intended tasks.
- `Command`: Commands are the specialised tasks you want your agents to perform (like answering developer's query, refactoring, code generation, etc).
- `DataSource`: Data sources are crucial for providing your agent with the information it needs. This could be anything from official documentation, blog posts, code examples, or even custom knowledge bases. In the example above, docsSource and blogsSource represent potential data sources.
- `Command`: Commands define the specialized actions your agent can perform. These are like building blocks for more complex tasks. The example uses the AskCommand which allows your agent to answer user queries based on the provided docsSource.
- `Metadata`: Metadata provides information about your agent, such as its name, display avatar, and associated tags. This helps users understand what the agent is about and how it can be used.
- `System Prompt`: The system prompt sets the initial context for your agent. This is like giving it instructions or defining its persona. In this example, the prompt makes it clear that "My Agent" is a Flutter expert, how it should handle responses, and the desired level of detail in its answers.

### Datasource

As described above data sources let you attach the data that your agent will need to perform its tasks. It can be anything from raw texts, JSON, file data, or even webpages.
As described above data sources let you attach the data that your agent will need to perform its tasks. It can be anything from raw texts, JSON, file data, or webpages or even repos.

Example for DataSource:

Expand All @@ -73,11 +90,12 @@ class DocsDataSource extends DataSource {
/// Enables your agent to use web pages by indexing specified web page
/// URLs or sitemaps in the object.
/// URLs or sitemaps or even github repos in the object.
@override
List<WebDataObject> get webObjects =>
[WebDataObject.fromWebPage('https://sampleurl.com'),
WebDataObject.fromSiteMap('https://sampleurl.com/sitemap.xml')];
WebDataObject.fromSiteMap('https://sampleurl.com/sitemap.xml'),
WebDataObject.fromGithub('https://github.com/user/repo', '<personal access token>', CodeFilter(pathRegex: '.*\.dart'), IssueFilter(labels: ['bug']))];
}
```

Expand Down
Loading

0 comments on commit 8070ce0

Please sign in to comment.