@scout9/app 1.0.0-alpha.0.5.3 → 1.0.0-alpha.0.5.4
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/dist/{dev-be9ba80f.cjs → dev-7e3c6095.cjs} +99 -57
- package/dist/{index-11e312c6.cjs → index-4dfed9d3.cjs} +54 -44
- package/dist/index.cjs +3 -3
- package/dist/{macros-57f9b28b.cjs → macros-c8392690.cjs} +6 -2
- package/dist/{multipart-parser-8a217889.cjs → multipart-parser-65dc2a0b.cjs} +3 -3
- package/dist/schemas.cjs +1 -1
- package/dist/testing-tools.cjs +2 -2
- package/package.json +1 -1
- package/src/core/config/agents.js +2 -3
- package/src/core/config/commands.js +38 -28
- package/src/core/config/entities.js +17 -9
- package/src/core/config/index.js +3 -2
- package/src/core/config/workflow.js +11 -5
- package/src/core/index.js +2 -3
- package/src/report.js +8 -2
- package/src/runtime/schemas/conversation.js +41 -36
- package/src/testing-tools/dev.js +370 -364
- package/src/utils/configs/agents.js +2 -1
- package/src/utils/configs/entities.js +14 -4
- package/src/utils/configs/workflow.js +42 -35
- package/src/utils/project.js +2 -1
- package/types/index.d.ts +79 -2
- package/types/index.d.ts.map +1 -1
|
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises';
|
|
|
3
3
|
import colors from 'kleur';
|
|
4
4
|
import { globSync } from 'glob';
|
|
5
5
|
import { Configuration, Scout9Api } from '@scout9/admin';
|
|
6
|
-
import { checkVariableType, requireProjectFile } from '../../utils/index.js';
|
|
6
|
+
import { checkVariableType, requireProjectFile, simplifyError } from '../../utils/index.js';
|
|
7
7
|
import { AgentsSchema, AgentsConfigurationSchema } from '../../runtime/index.js';
|
|
8
8
|
import { audioExtensions } from '../../utils/audio-type.js';
|
|
9
9
|
import { fileTypeFromBuffer } from '../../utils/file-type.js';
|
|
@@ -315,8 +315,7 @@ export default async function loadAgentConfig({
|
|
|
315
315
|
|
|
316
316
|
const result = (deploying ? AgentsConfigurationSchema : AgentsSchema).safeParse(agents);
|
|
317
317
|
if (!result.success) {
|
|
318
|
-
result.error
|
|
319
|
-
throw result.error;
|
|
318
|
+
throw simplifyError(result.error);
|
|
320
319
|
}
|
|
321
320
|
|
|
322
321
|
if (serverDeployed) {
|
|
@@ -1,41 +1,51 @@
|
|
|
1
1
|
import { globSync } from 'glob';
|
|
2
|
-
import { CommandsSchema } from '../../runtime/index.js';
|
|
2
|
+
import { CommandSchema, CommandsSchema } from '../../runtime/index.js';
|
|
3
3
|
import { basename, dirname } from 'node:path';
|
|
4
|
+
import { simplifyError } from '../../utils/index.js';
|
|
5
|
+
import { logUserValidationError } from '../../report.js';
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @returns {Promise<CommandConfiguration[]>}
|
|
8
10
|
*/
|
|
9
11
|
export default async function loadCommandsConfig(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
{
|
|
13
|
+
cwd = process.cwd(),
|
|
14
|
+
src = 'src',
|
|
15
|
+
cb = (message) => {
|
|
16
|
+
}
|
|
17
|
+
} = {}
|
|
15
18
|
) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
// const config = globSync(path.resolve(cwd, `${src}/workflows/**/workflow.{ts,js}`), {cwd, absolute: true})
|
|
20
|
+
const config = globSync(`${src}/commands/**/{index,command,*.command}.{ts,js}`, {cwd, absolute: false})
|
|
21
|
+
.map((path) => {
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
23
|
+
const dir = dirname(path);
|
|
24
|
+
let entity = basename(path).replace(/\..*$/, ''); // Removes any "."'s
|
|
25
|
+
if (!entity) {
|
|
26
|
+
throw new Error(`Invalid command path "${path}"`);
|
|
27
|
+
}
|
|
28
|
+
switch (entity) {
|
|
29
|
+
case 'index':
|
|
30
|
+
case 'command':
|
|
31
|
+
entity = basename(dir);
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return CommandSchema.parse({
|
|
36
|
+
entity,
|
|
37
|
+
path: path.split(src + '/commands/')[1]
|
|
38
|
+
});
|
|
39
|
+
} catch (e) {
|
|
40
|
+
throw logUserValidationError(e, path);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
// Validate the config
|
|
45
|
+
try {
|
|
46
|
+
return CommandsSchema.parse(config);
|
|
47
|
+
} catch (e) {
|
|
48
|
+
throw simplifyError(e);
|
|
49
|
+
}
|
|
39
50
|
|
|
40
|
-
return config;
|
|
41
51
|
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
EntityConfigurationSchema,
|
|
7
7
|
EntityRootProjectConfigurationSchema
|
|
8
8
|
} from '../../runtime/index.js';
|
|
9
|
-
import { checkVariableType, requireOptionalProjectFile, requireProjectFile } from '../../utils/index.js';
|
|
9
|
+
import { checkVariableType, requireOptionalProjectFile, requireProjectFile, simplifyError } from '../../utils/index.js';
|
|
10
10
|
import { logUserValidationError } from '../../report.js';
|
|
11
11
|
|
|
12
12
|
async function loadEntityApiConfig(cwd, filePath) {
|
|
@@ -23,8 +23,11 @@ async function loadEntityApiConfig(cwd, filePath) {
|
|
|
23
23
|
config[key] = true;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
try {
|
|
27
|
+
return EntityApiConfigurationSchema.parse(config);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
throw simplifyError(config);
|
|
30
|
+
}
|
|
28
31
|
} else {
|
|
29
32
|
return null;
|
|
30
33
|
}
|
|
@@ -81,8 +84,7 @@ export default async function loadEntitiesConfig(
|
|
|
81
84
|
// Validate entity configuration
|
|
82
85
|
const result = EntityConfigurationSchema.safeParse(entityConfig, {path: ['entities', config.length]});
|
|
83
86
|
if (!result.success) {
|
|
84
|
-
logUserValidationError(result.error, filePath);
|
|
85
|
-
throw result.error;
|
|
87
|
+
throw logUserValidationError(result.error, filePath);
|
|
86
88
|
}
|
|
87
89
|
} else if (isSpecial && (fileName === 'index' || fileName === 'config')) {
|
|
88
90
|
// If this is a special entity file, then ignore as we will capture it another method
|
|
@@ -96,7 +98,11 @@ export default async function loadEntitiesConfig(
|
|
|
96
98
|
entities: parents.reverse(),
|
|
97
99
|
api
|
|
98
100
|
};
|
|
99
|
-
|
|
101
|
+
try {
|
|
102
|
+
EntityRootProjectConfigurationSchema.parse(entityProjectConfig);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
throw simplifyError(e);
|
|
105
|
+
}
|
|
100
106
|
const existingIndex = config.findIndex(c => c.entity === entityProjectConfig.entity);
|
|
101
107
|
if (existingIndex > -1) {
|
|
102
108
|
if (config[existingIndex].entities.length !== entityProjectConfig.entities.length) {
|
|
@@ -134,8 +140,10 @@ export default async function loadEntitiesConfig(
|
|
|
134
140
|
}
|
|
135
141
|
|
|
136
142
|
// Validate the config
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
try {
|
|
144
|
+
return EntitiesRootProjectConfigurationSchema.parse(config);
|
|
145
|
+
} catch (e) {
|
|
146
|
+
throw simplifyError(e);
|
|
147
|
+
}
|
|
140
148
|
}
|
|
141
149
|
|
package/src/core/config/index.js
CHANGED
|
@@ -6,8 +6,9 @@ import loadEntitiesConfig from './entities.js';
|
|
|
6
6
|
import loadProjectConfig from './project.js';
|
|
7
7
|
import loadWorkflowsConfig from './workflow.js';
|
|
8
8
|
import { Scout9ProjectBuildConfigSchema } from '../../runtime/index.js';
|
|
9
|
-
import { ProgressLogger } from '../../utils/index.js';
|
|
9
|
+
import { ProgressLogger, simplifyError } from '../../utils/index.js';
|
|
10
10
|
import loadCommandsConfig from './commands.js';
|
|
11
|
+
import { logUserValidationError } from '../../report.js';
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
export function loadEnvConfig({
|
|
@@ -65,7 +66,7 @@ export async function loadConfig({
|
|
|
65
66
|
const result = Scout9ProjectBuildConfigSchema.safeParse(projectConfig);
|
|
66
67
|
if (!result.success) {
|
|
67
68
|
result.error.source = `${src}/index.js`;
|
|
68
|
-
throw result.error;
|
|
69
|
+
throw logUserValidationError(result.error, `${src}/index.js`);
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
return projectConfig;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { globSync } from 'glob';
|
|
2
2
|
import { WorkflowConfigurationSchema, WorkflowsConfigurationSchema } from '../../runtime/index.js';
|
|
3
|
+
import { logUserValidationError } from '../../report.js';
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -35,13 +36,18 @@ export default async function loadWorkflowsConfig(
|
|
|
35
36
|
entity: parents[0],
|
|
36
37
|
entities: parents.reverse(),
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
try {
|
|
40
|
+
return WorkflowConfigurationSchema.parse(workflowConfig);
|
|
41
|
+
} catch (e) {
|
|
42
|
+
throw logUserValidationError(e, path);
|
|
43
|
+
}
|
|
41
44
|
});
|
|
42
45
|
|
|
43
46
|
// Validate the config
|
|
44
|
-
|
|
47
|
+
try {
|
|
48
|
+
return WorkflowsConfigurationSchema.parse(config);
|
|
49
|
+
} catch (e) {
|
|
50
|
+
throw logUserValidationError(e, src);
|
|
51
|
+
}
|
|
45
52
|
|
|
46
|
-
return config;
|
|
47
53
|
}
|
package/src/core/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import path from 'node:path';
|
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import fetch, { FormData } from 'node-fetch';
|
|
8
8
|
import { Configuration, Scout9Api } from '@scout9/admin';
|
|
9
|
-
import { checkVariableType, ProgressLogger, requireProjectFile } from '../utils/index.js';
|
|
9
|
+
import { checkVariableType, ProgressLogger, requireProjectFile, simplifyError } from '../utils/index.js';
|
|
10
10
|
import decompress from 'decompress';
|
|
11
11
|
import { loadUserPackageJson } from './config/project.js';
|
|
12
12
|
import { platformApi } from './data.js';
|
|
@@ -300,8 +300,7 @@ export async function getAgentContacts() {
|
|
|
300
300
|
export async function run(event, {eventSource} = {}) {
|
|
301
301
|
const result = WorkflowEventSchema.safeParse(event);
|
|
302
302
|
if (!result.success) {
|
|
303
|
-
logUserValidationError(result.error, eventSource);
|
|
304
|
-
throw result.error;
|
|
303
|
+
throw logUserValidationError(result.error, eventSource);
|
|
305
304
|
}
|
|
306
305
|
const configuration = new Configuration({
|
|
307
306
|
apiKey: process.env.SCOUT9_API_KEY
|
package/src/report.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { red, cyan, green, dim, white, grey, bold, italic, magenta, yellow } from 'kleur/colors';
|
|
2
|
-
import { ProgressLogger } from './utils/index.js';
|
|
2
|
+
import { ProgressLogger, simplifyError } from './utils/index.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
*
|
|
6
6
|
* @param {import('zod').ZodError} zodError
|
|
7
7
|
* @param {string} source
|
|
8
|
+
* @returns {import('zod-validation-error').ValidationError}
|
|
8
9
|
*/
|
|
9
10
|
export function logUserValidationError(
|
|
10
11
|
zodError,
|
|
11
12
|
source,
|
|
12
13
|
) {
|
|
13
|
-
const issues = zodError
|
|
14
|
+
const issues = zodError?.issues || [];
|
|
14
15
|
|
|
15
16
|
console.log(red(`Scout9 Schema Validation Error at ${bold(source)}, fix these issues and rerun`));
|
|
16
17
|
for (const {code, expected, received, path, message} of issues) {
|
|
@@ -29,6 +30,11 @@ export function logUserValidationError(
|
|
|
29
30
|
}
|
|
30
31
|
console.log('\t', objectPath, grey(`${text}`));
|
|
31
32
|
}
|
|
33
|
+
|
|
34
|
+
const simplifiedError = simplifyError(zodError);
|
|
35
|
+
console.error(`\n${red(simplifiedError.message)}\n`);
|
|
36
|
+
|
|
37
|
+
return simplifiedError;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
|
|
@@ -1,47 +1,52 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { zId } from './utils.js';
|
|
3
|
+
import { CommandsSchema } from './workflow.js';
|
|
3
4
|
|
|
4
5
|
export const ConversationContext = z.record(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
z.union([
|
|
7
|
+
z.any(),
|
|
8
|
+
z.string(),
|
|
9
|
+
z.number(),
|
|
10
|
+
z.boolean(),
|
|
11
|
+
z.null(),
|
|
12
|
+
z.array(
|
|
13
|
+
z.union([z.string(), z.number(), z.boolean(), z.null()])
|
|
14
|
+
)
|
|
15
|
+
])
|
|
15
16
|
);
|
|
16
17
|
|
|
17
18
|
export const ConversationAnticipateSchema = z.object({
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
type: z.enum(['did', 'literal', 'context'], {description: 'Determines the runtime to address the next response'}),
|
|
20
|
+
slots: z.record(z.string(), z.array(z.any())),
|
|
21
|
+
did: z.string({description: 'For type \'did\''}).optional(),
|
|
22
|
+
map: z.array(z.object({
|
|
23
|
+
slot: z.string(),
|
|
24
|
+
keywords: z.array(z.string())
|
|
25
|
+
}), {description: 'For literal keywords, this map helps point which slot the keyword matches to'}).optional()
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
export const ConversationSchema = z.object({
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
$id: zId('Conversation ID', z.string({description: 'Conversation unique id'})),
|
|
30
|
+
$agent: zId('Conversation Agent ID', z.string({description: 'Default agent assigned to the conversation(s)'})),
|
|
31
|
+
$customer: zId('Conversation Customer ID', z.string({description: 'Customer this conversation is with'})),
|
|
32
|
+
initialContexts: z.array(z.string(), {description: 'Initial contexts to load when starting the conversation'})
|
|
33
|
+
.optional(),
|
|
34
|
+
environment: z.enum(['phone', 'email', 'web']),
|
|
35
|
+
environmentProps: z.object({
|
|
36
|
+
subject: z.string({description: 'HTML Subject of the conversation'}).optional(),
|
|
37
|
+
platformEmailThreadId: z.string({description: 'Used to sync email messages with the conversation'}).optional()
|
|
38
|
+
}).optional(),
|
|
39
|
+
locked: z.boolean({description: 'Whether the conversation is locked or not'}).optional().nullable(),
|
|
40
|
+
lockedReason: z.string({description: 'Why this conversation was locked'}).optional().nullable(),
|
|
41
|
+
lockAttempts: z.number({description: 'Number attempts made until conversation is locked'}).optional().nullable(),
|
|
42
|
+
forwardedTo: z.string({description: 'What personaId/phone/email was forwarded'}).optional().nullable(),
|
|
43
|
+
forwarded: z.string({description: 'Datetime ISO 8601 timestamp when persona was forwarded'}).optional().nullable(),
|
|
44
|
+
forwardNote: z.string().optional().nullable(),
|
|
45
|
+
intent: z.string({description: 'Detected intent of conversation'}).optional().nullable(),
|
|
46
|
+
intentScore: z.number({description: 'Confidence score of the assigned intent'}).optional().nullable(),
|
|
47
|
+
anticipate: ConversationAnticipateSchema.optional(),
|
|
48
|
+
/**
|
|
49
|
+
* Whether this conversation is part of a command flow
|
|
50
|
+
*/
|
|
51
|
+
command: CommandsSchema.optional()
|
|
47
52
|
});
|