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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sre",
"version": "0.0.15",
"version": "0.1.0",
"description": "",
"author": "Alaa-eddine KADDOURI",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@smythos/cli",
"version": "0.2.16",
"version": "0.2.20",
"description": "SmythOS SRE Command Line Interface",
"keywords": [
"smythos",
Expand Down
142 changes: 92 additions & 50 deletions packages/cli/src/commands/create/create.index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const detectApiKeys = () => {
const keys: { [key: string]: string | undefined } = {
openai: process.env.OPENAI_API_KEY ? '$env(OPENAI_API_KEY)' : undefined,
anthropic: process.env.ANTHROPIC_API_KEY ? '$env(ANTHROPIC_API_KEY)' : undefined,
google: process.env.GOOGLE_API_KEY ? '$env(GOOGLE_API_KEY)' : undefined,
googleai: process.env.GOOGLE_API_KEY ? '$env(GOOGLE_API_KEY)' : process.env.GEMINI_API_KEY ? '$env(GEMINI_API_KEY)' : undefined,
};

return Object.entries(keys).reduce((acc, [key, value]) => {
Expand Down Expand Up @@ -153,6 +153,8 @@ async function RunProject(projectNameArg?: string) {
.map((k) => chalk.cyan(k))
.join(', ');

const existingVault = fs.existsSync(vaultFile) ? JSON.parse(fs.readFileSync(vaultFile, 'utf8')) : null;

const initialAnswers = await inquirer.prompt([
{
type: 'input',
Expand Down Expand Up @@ -204,17 +206,63 @@ async function RunProject(projectNameArg?: string) {

answers.projectName = projectName;

console.log(chalk.yellowBright(`\n===[ Now let's configure Smyth Resources folder ]===`));
console.log(
`${chalk.gray(
'Some connectors in SmythOS might need to store data locally, in order to keep things clean, we store all SmythOS related data in a single place.\n'
)}`
);

const resourcesAnswers = await inquirer.prompt([
{
type: 'list',
name: 'smythResources',
message: 'Smyth Resources Folder',
suffix: `\n${chalk.magenta('Location where we can store data like logs, cache, etc. (Use arrow keys ↑↓)')}\n`,
choices: [
{ name: `Shared folder in the ${chalk.underline('user home directory')} (~/.smyth)`, value: path.join(os.homedir(), '.smyth') },
{
name: `Local folder under ${chalk.underline('project root')} (./${path.basename(answers.targetFolder)}/.smyth)`,
value: path.join(answers.targetFolder, '.smyth'),
},
],
default: 0,
},
]);

const isSharedResources = resourcesAnswers.smythResources === path.join(os.homedir(), '.smyth');
let _useSharedVault = isSharedResources;

let vault: { [key: string]: string } = {};

let _useSharedVault = false;
//let _useSharedVault = false;

console.log(chalk.yellowBright(`\n===[ Now let's set your secrets ]===`));
console.log(
`${chalk.gray(
'SmythOS uses a vault to store your secrets. Set your secrets once, they’ll be securely stored and loaded by the SDK only when needed.This keeps LLM API keys out of your code.\n'
)}`
);

if (_useSharedVault && vaultFile) {
console.log(chalk.magenta(` ℹ We will use Vault file found in your shared folder ${vaultFile}`));
const existingProviders = Object.keys(existingVault?.default).filter((p) => existingVault?.default[p]);
if (existingProviders.length > 0) {
console.log(chalk.magenta(` ℹ API keys already present in your shared vault: ${existingProviders.join(', ')}`));
}
vault = {
openai: '#',
anthropic: '#',
googleai: '#',
groq: '#',
togetherai: '#',
xai: '#',
deepseek: '#',
tavily: '#',
scrapfly: '#',
...(existingVault?.default || {}),
};
}
/*
if (vaultFile) {
console.log(chalk.magenta(` ℹ I found an existing shared vault file ${vaultFile}`));
const { useSharedVault } = await inquirer.prompt([
Expand All @@ -238,7 +286,9 @@ async function RunProject(projectNameArg?: string) {
scrapfly: '#',
};
}
*/

/*
if (hasDetectedKeys && !_useSharedVault) {
const { useDetectedKeys } = await inquirer.prompt([
{
Expand All @@ -252,50 +302,37 @@ async function RunProject(projectNameArg?: string) {
vault = { ...detectedKeys };
}
}
*/

const allProviders = ['openai', 'anthropic', 'google'];
const allProviders = ['openai', 'anthropic', 'googleai'];
const missingKeyQuestions = allProviders
.filter((provider) => !vault[provider] || vault[provider] === '#')
.map((provider) => ({
type: 'input',
name: provider,
message: `Enter your ${provider.charAt(0).toUpperCase() + provider.slice(1)} API Key (Enter value, or press Enter to skip)\n`,
}));

if (!_useSharedVault && missingKeyQuestions.length > 0) {
.map((provider) => {
if (hasDetectedKeys && detectedKeys[provider]) {
return {
type: 'confirm',
name: provider,
message: `We detected that ${provider} API Key is present in your environment variables. Do you want to use the environment variable in your project's vault?`,
default: true,
};
}
return {
type: 'input',
name: provider,
message: `Enter your ${provider.charAt(0).toUpperCase() + provider.slice(1)} API Key (Enter value, or press Enter to skip)\n`,
};
});

if (missingKeyQuestions.length > 0) {
const keyAnswers = await inquirer.prompt(missingKeyQuestions);
for (const [provider, key] of Object.entries(keyAnswers)) {
if (key) {
vault[provider] = key as string;
vault[provider] = key === true ? detectedKeys[provider] : (key as string);
}
}
}

console.log(chalk.yellowBright(`\n===[ Now let's configure Smyth Resources folder ]===`));
console.log(
`${chalk.gray(
'Some connectors in SmythOS might need to store data locally, in order to keep things clean, we store all SmythOS related data in a single place.\n'
)}`
);

const remainingAnswers = await inquirer.prompt([
{
type: 'list',
name: 'smythResources',
message: 'Smyth Resources Folder',
suffix: `\n${chalk.magenta('Location where we can store data like logs, cache, etc. (Use arrow keys ↑↓)')}\n`,
choices: [
{ name: `Shared folder in the ${chalk.underline('user home directory')} (~/.smyth)`, value: path.join(os.homedir(), '.smyth') },
{
name: `Local folder under ${chalk.underline('project root')} (./${path.basename(answers.targetFolder)}/.smyth)`,
value: path.join(answers.targetFolder, '.smyth'),
},
],
default: 0,
},
]);

answers = { ...answers, ...remainingAnswers };
answers = { ...answers, ...resourcesAnswers };

const finalConfig = {
projectName: answers.projectName,
Expand Down Expand Up @@ -404,21 +441,26 @@ async function createProject(config: any) {
}

//Write vault file
if (!config.useSharedVault) {
const vaultPath = path.join(config.smythResources, '.sre', 'vault.json');

//always create a default vault even if no key is configured
if (!fs.existsSync(vaultPath)) {
const vaultData = {
default: {
...vaultTemplate.default,
...config.vault,
},
};
fs.writeFileSync(vaultPath, JSON.stringify(vaultData, null, 2));
}
//if (!config.useSharedVault) {
const vaultPath = path.join(config.smythResources, '.sre', 'vault.json');

//always create a default vault even if no key is configured
if (fs.existsSync(vaultPath)) {
//make a backup
const backupPath = path.join(config.smythResources, '.sre', 'vault.json.backup');
fs.copyFileSync(vaultPath, backupPath);
}

const vaultData = {
default: {
...vaultTemplate.default,
...config.vault,
},
};
fs.writeFileSync(vaultPath, JSON.stringify(vaultData, null, 2));

//}

//update package.json with project name
const packageJsonPath = path.join(projectFolder, 'package.json');
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
Expand Down
86 changes: 86 additions & 0 deletions packages/core/docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# SRE Configuration

SRE provides several ways to configure its behavior, including environment variables, command-line arguments, and settings files. This document outlines the available configuration methods and settings.

## Configuration Layers

Configuration is applied in the following order of precedence (higher numbers override lower numbers):

1. **Default values:** Hardcoded defaults within the application.
2. **User settings folder (~/.smyth/):** Global settings for the current user's home directory.
3. **Project settings folder (.smyth/):** Project-specific settings.
4. **Environment variables:** System-wide or session-specific variables, which may be loaded from `.env` files.
5. **User Code:** User code can override configuration by passing a custom config to SRE and its connectors.

## The .smyth Folder

SRE uses `.smyth` folders to store configuration, secrets, and some persistent data used by connectors:

### Location

The `.smyth` folder can be located in two places:

- **User settings folder:**

- **Location:** `~/.smyth/` (where `~` is your home directory).
- **Scope:** Applies to all SRE sessions for the current user.

- **Project settings folder:**
- **Location:** `.smyth/` within your project's root directory.
- **Scope:** Applies only when running SRE from that specific project. Project settings override user settings.

### Content

In this section, ".smyth" refers to either the user settings folder or the project settings folder, depending on the discovery order.

#### .smyth/.sre/ Subfolder

This subfolder contains the actual settings for SRE.

- `.smyth/.sre/vault.json`: This file is present if you are using the default vault connector to manage API keys and secrets. It contains LLM API keys, other third-party API keys, and user-specified keys. It can be encrypted to protect the keys. (You can use other vault connectors to manage your secrets, such as AWS Secret Manager. In that case, this file will be ignored.)

- `.smyth/.sre/config.json`: If present, this file defines the SRE startup configuration.

#### Other Subfolders

SRE can load connectors that need to store data locally. These connectors can be configured to store data in specific locations, but if no location is specified, they fall back to a default location, which is a subfolder of the `.smyth` folder.

For example, the Local Storage connector uses the `.smyth/storage/` folder to store local data if no other location is specified.

**Note on environment variables in settings:** String values within your `vault.json` or `config.json` files can reference environment variables using the `$env(VAR_NAME)` syntax. These variables will be automatically resolved at runtime. For example, if you have an environment variable `OPENAI_API_KEY`, you could use it in `vault.json` like this: `"openai": "$env(OPENAI_API_KEY)"`.

### vault.json Structure

The vault stores keys for different teams, but must have at least a "default" team configured. This is the team ID used for any agent that does not belong to a specific team. If an agent belongs to a specific team, it can only load secrets from that team's vault by default. The vault connector provides a configuration option to specify a shared vault entry that can be used as a fallback if a key is not found in the team's vault. This can be a completely separate entry (for example, called "shared"), or you can specify an existing entry (e.g., "default").

```json
{
"default": {
"echo": "",
"openai": "sk-hardcoded-key",
"anthropic": "$env(ANTHROPIC_API_KEY)",
"googleai": "",
"groq": "",
"togetherai": "",
"tavily": "",
"my_custom_key": "1234567890"
},
"team-id-0001": {
"echo": "...",
"openai": "...",
"anthropic": "...",
"googleai": "...",
"groq": "...",
"togetherai": "...",
"tavily": "...",
"my_custom_key": "..."
},
"team-id-0002": {
//...
}
}
```

### config.json Structure

(TBD)
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@smythos/sre",
"version": "1.5.16",
"version": "1.5.20",
"description": "Smyth Runtime Environment",
"author": "Alaa-eddine KADDOURI",
"license": "MIT",
Expand Down
48 changes: 45 additions & 3 deletions packages/sdk/docs/01-getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,42 @@ The code in this guide is a more detailed version of the script found in [`examp

## 1. Installation

First, you need to install the SmythOS SDK. Since this is a `pnpm` workspace, we'll use that. Open your terminal and run:
### Method 1: Using the CLI (Recommended)

The easiest way to get started is by using the SmythOS CLI to scaffold a new project:

```bash
# Install the CLI globally
npm i -g @smythos/cli

# Create a new project
sre create "My First Agent"
```

The CLI will guide you step-by-step to create your SDK project with the right configuration for your needs. Select **Empty Project** template when prompted.

### Method 2: Direct SDK Installation

If you prefer to add the SDK to an existing project, we recommend cloning one of our project templates:

```bash
pnpm install @smythos/sdk
# Clone a template (replace 'template-name' with your desired template)
git clone -b template-name https://github.com/SmythOS/sre-project-templates.git my-agent-project
cd my-agent-project
npm install
```

Available templates:

- `empty-sdk-template` - Blank SDK project
- `minimal-sdk-agent` - Basic agent implementation
- `interactive-book-assistant` - Fully functional agent with interactive chat
- `interactive-chat-two-agents` - Two different agent implementations

Alternatively, you can install the SDK directly in an existing project:

```bash
npm install @smythos/sdk
```

The SDK is designed for a frictionless start. It automatically initializes the Smyth Runtime Environment (SRE) with in-memory components, so you can start building agents right away without any complex setup.
Expand Down Expand Up @@ -69,7 +101,17 @@ main();

## 3. Run Your Code

Save the file and run it from your terminal:
If you used the CLI to create your project, build and run it:

```bash
# Build the project
npm run build

# Run your agent
npm start
```

If you're using direct SDK installation, save the file and run it from your terminal:

```bash
ts-node index.ts
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@smythos/sdk",
"version": "1.0.12",
"version": "1.0.20",
"description": "SRE SDK",
"keywords": [
"smythos",
Expand Down