Skip to content

Commit

Permalink
feat(cursorrules): add new cursorrules file
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelmansuy committed Sep 3, 2024
1 parent aaf963c commit 2096982
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 51 deletions.
55 changes: 55 additions & 0 deletions .cursorrules
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
## Role and Expertise:

You are an elite software engineer and product manager with the following expertise:

- Extensive experience in implementing multi-provider architectures for Large Language Models (LLMs)
- Master of functional programming, especially in TypeScript
- Deep understanding of TypeScript and its ecosystem
- Expert at creating code libraries with APIs that delight developers
- Advocate for composability, immutability, and simple pragmatic solutions
- Prefer Function over Class if possible
- Prefer Types over Interfaces if possible

## Coding Standards:

### Naming Conventions:
- Use kebab-case for file names (e.g., `my-component.ts`)
- Use camelCase for variables and function names (e.g., `myVariable`, `myFunction()`)
- Use UpperCamelCase (PascalCase) for classes, types, and interfaces (e.g., `MyClass`, `MyInterface`)
- Use ALL_CAPS for constants and enum values (e.g., `MAX_COUNT`, `Color.RED`)

### File Organization:
- Group related functionality into modules
- Use index files to simplify imports
- Separate concerns: keep business logic, UI components, and utilities in different directories

### Code Style:
- Prefer `const` over `let` when variables won't be reassigned
- Use arrow functions for better lexical scoping and concise syntax
- Utilize TypeScript's type system fully: use interfaces, type aliases, and generics where appropriate
- Implement error handling with custom error types
- Write pure functions where possible to improve testability and reduce side effects

### Best Practices:
- Follow the Single Responsibility Principle
- Use dependency injection to improve testability and flexibility
- Implement proper error handling and logging
- Write comprehensive unit tests for all business logic
- Use async/await for asynchronous operations instead of callbacks or raw promises
- Leverage TypeScript's strict mode for enhanced type checking

### Documentation:
- Use JSDoc comments for functions, classes, and complex types
- Include examples in documentation where appropriate
- Keep README files up-to-date with setup instructions, usage examples, and contribution guidelines

## Library Usage:
Utilize the following libraries effectively:
- axios (^1.7.5): For HTTP requests, implement interceptors for global error handling and authentication
- js-yaml (^4.1.0): For parsing and stringifying YAML, use type-safe schemas
- mime-types (^2.1.35): For MIME type detection and file extension mapping
- node-gyp (^10.2.0): For native addon build tool, ensure proper setup in your build pipeline
- uuid (^10.0.0): For generating unique identifiers, prefer v4 for random UUIDs
- zod (^3.23.8): For runtime type checking and data validation, create reusable schemas


15 changes: 7 additions & 8 deletions packages/qllm-cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,21 +157,21 @@ QLLM CLI stores its configuration in a JSON file located at `~/.qllmrc`. While m

QLLM CLI offers a variety of commands for interacting with LLMs. Here's an overview of the primary usage patterns:

### Asking Questions
### Running Templates

For one-time queries, use the `ask` command:
QLLM CLI allows you to run templates directly. This is now the default behavior when no specific command is provided:

```bash
qllm ask "What is the capital of France?"
qllm <template_url>
```

Specify a provider and model:
For example:

```bash
qllm ask "Explain quantum computing" -p openai -m gpt-4
qllm https://raw.githubusercontent.com/quantalogic/qllm/main/prompts/chain_of_thought_leader.yaml
```

The `ask` command supports various options:
The `run` command supports various options:

- `-p, --provider <provider>`: Specify the LLM provider (default: openai)
- `-m, --model <model>`: Choose a specific model
Expand Down Expand Up @@ -212,8 +212,7 @@ qllm ask "Write a short story about AI" -s

````bash
qllm ask "Explain the theory of relativity" -o relativity_explanation.txt


```

### Interactive Chat

Expand Down
7 changes: 7 additions & 0 deletions packages/qllm-cli/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@ import tseslint from "typescript-eslint";
export default tseslint.config(
{
ignores: ["**/node_modules/**", "**/dist/**"],
"settings": {
"env": {
"node": true,
},
},
},
eslint.configs.recommended,
...tseslint.configs.recommended,
{

rules: {
"@typescript-eslint/no-unused-vars": [
"warn",
Expand All @@ -28,5 +34,6 @@ export default tseslint.config(
"no-useless-catch": "warn", // Changed from 'error' to 'warn',
"no-throw-literal": "warn", // Example rule to treat literal throws as warnings
},

},
);
34 changes: 21 additions & 13 deletions packages/qllm-cli/src/commands/run-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { processAndExit } from "../utils/common";
import { parseVariables } from "../utils/template-utils";
import { writeToFile } from "../utils/write-file";

declare var process: NodeJS.Process; //eslint-disable-line

const runAction = async (
templateSource: string,
options: Partial<RunCommandOptions>,
Expand Down Expand Up @@ -106,12 +108,12 @@ const setupExecutor = (ioManager: IOManager, spinner: Spinner) => {
const executor = new TemplateExecutor();

executor.on("streamChunk", (chunk: string) => process.stdout.write(chunk));
executor.on("streamComplete", (response: string) => {});
executor.on("streamError", (error: any) => {
executor.on("streamComplete", (_response: string) => {});
executor.on("streamError", (error: unknown) => {
spinner.stop();
ioManager.displayError(`Error during completion: ${error}`);
});
executor.on("requestSent", (request: any) => {
executor.on("requestSent", (request: unknown) => {
const length = JSON.stringify(request).length;
spinner.start();
spinner.update({
Expand All @@ -122,7 +124,7 @@ const setupExecutor = (ioManager: IOManager, spinner: Spinner) => {
spinner.update({ text: "" });
spinner.stop();
});
executor.on("executionError", (error: any) => {
executor.on("executionError", (error: unknown) => {
spinner.stop();
ioManager.displayError(`Error executing template: ${error}`);
});
Expand All @@ -136,7 +138,7 @@ const setupExecutor = (ioManager: IOManager, spinner: Spinner) => {
};

const handleOutput = async (
result: any,
result: unknown,
validOptions: RunCommandOptions,
ioManager: IOManager,
) => {
Expand All @@ -148,18 +150,21 @@ const handleOutput = async (
};

const handleExtractedOutput = async (
result: any,
result: unknown,
validOptions: RunCommandOptions,
ioManager: IOManager,
) => {
const extractedVariables = validOptions
.extract!.split(",")
.map((v) => v.trim());
const extractedData: Record<string, any> = {};
const extractedData: Record<string, any> = {}; //eslint-disable-line

// Cast result to a known type
const outputResult = result as { outputVariables: Record<string, any> }; //eslint-disable-line

for (const variable of extractedVariables) {
if (result.outputVariables.hasOwnProperty(variable)) {
extractedData[variable] = result.outputVariables[variable];
if (outputResult.outputVariables.hasOwnProperty(variable)) { //eslint-disable-line
extractedData[variable] = outputResult.outputVariables[variable];
} else {
ioManager.displayWarning(
`Variable "${variable}" not found in the output.`,
Expand All @@ -182,7 +187,7 @@ const handleExtractedOutput = async (
};

const handleFullOutput = async (
result: any,
result: any, //eslint-disable-line
validOptions: RunCommandOptions,
ioManager: IOManager,
) => {
Expand All @@ -200,20 +205,20 @@ const handleFullOutput = async (
};

const displayExtractedVariables = (
variables: Record<string, any>,
variables: Record<string, unknown>,
ioManager: IOManager,
) => {
ioManager.displayInfo("Output Variables:");
for (const [key, value] of Object.entries(variables)) {
ioManager.displayInfo(`${ioManager.colorize(key, "green")}:`);
ioManager.displayInfo(`${ioManager.colorize(value, "yellow")}`);
ioManager.displayInfo(`${ioManager.colorize(value as string, "yellow")}`);
ioManager.displayInfo("-------------------------");
}
};

export const runCommand = new Command("run")
.description("Execute a template")
.argument("<template>", "Template name, file path, or URL")
.argument("[template]", "Template name, file path, or URL")
.option(
"-t, --type <type>",
"Template source type (file, url, inline)",
Expand Down Expand Up @@ -244,3 +249,6 @@ export const runCommand = new Command("run")
runAction(templateSource, options),
),
);

// Export runAction for use in the main file
export { runAction };
77 changes: 47 additions & 30 deletions packages/qllm-cli/src/qllm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,25 @@ import { listCommand } from "./commands/list-command";
import { chatCommand } from "./commands/chat-command";
import { CliConfigManager } from "./utils/cli-config-manager";
import { configureCommand } from "./commands/configure-command";
import { runCommand } from "./commands/run-command";
import { runCommand, runAction } from "./commands/run-command";
import { readFileSync } from "fs";
import { join } from "path";
import { IOManager } from "./utils/io-manager";
import path from 'path';

declare var __dirname: string; //eslint-disable-line
declare var process: NodeJS.Process; //eslint-disable-line


// Read version from package.json
const packageJson = JSON.parse(
readFileSync(join(__dirname, "..", "package.json"), "utf-8"),
readFileSync(path.resolve(__dirname, "..", "package.json"), "utf-8"),
);


const VERSION = packageJson.version;

const ioManager = new IOManager();

export async function main() {
try {
const program = new Command();
Expand All @@ -36,53 +44,62 @@ export async function main() {
await configManager.ensureConfigFileExists();
await configManager.load();

// Add the ask command
// Add the run command as a named command
program.addCommand(runCommand);

// Set the run command as the default command
program
.argument("[template]", "Template name, file path, or URL")
.option("-t, --type <type>", "Template source type (file, url, inline)", "file")
.option("-v, --variables <variables>", "Template variables in JSON format")
.option("-p, --provider <provider>", "LLM provider to use")
.option("-m, --model <model>", "Specific model to use")
.option("--max-tokens <maxTokens>", "Maximum number of tokens to generate", parseInt)
.option("--temperature <temperature>", "Temperature for response generation", parseFloat)
.option("-s, --stream", "Stream the response")
.option("-o, --output <output>", "Output file for the response")
.option("-e, --extract <variables>", "Variables to extract from the response, comma-separated")
.action(async (template, options, command) => {
if (!template) {
command.help();
} else {
await runAction(template, options);
}
});

// Add other commands
program.addCommand(askCommand);

// Add the list command
program.addCommand(listCommand);

// Add chat command
program.addCommand(chatCommand);

// Add the configure command
program.addCommand(configureCommand);

// Add to program commands
program.addCommand(runCommand);

// Add other commands here as needed
// For example:
// program.addCommand(generateEmbeddingCommand);

// Set up the exit handler
// Set up the exit handler
// Set up the exit handler
process.on("exit", (code) => {
process.exit(code);
});

await program.parseAsync(process.argv);
} catch (error) {
console.error("An error occurred:", error);
ioManager.displayError(
`An error occurred: ${(error as Error).message}`,
);
process.exit(1);
} finally {
try {
// Any cleanup code if needed
} catch (error) {
console.error(
"An error occurred while saving the configuration:",
error,
ioManager.displayError(
`An error occurred while saving the configuration: ${(error as Error).message}`,
);
}
}
}

// Run the CLI
if (require.main === module) {
main().catch((error) => {
console.error("Unhandled error:", error);
process.exit(1);
});
}
main()
.catch((error) => {
ioManager.displayError(`Unhandled error: ${error}`);
process.exit(1);
});


export default main;

0 comments on commit 2096982

Please sign in to comment.