newo 3.0.0 → 3.1.0
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/CHANGELOG.md +337 -347
- package/README.md +111 -0
- package/dist/api.d.ts +7 -1
- package/dist/api.js +36 -0
- package/dist/auth.js +4 -0
- package/dist/cli/commands/help.js +10 -0
- package/dist/cli/commands/sandbox.d.ts +14 -0
- package/dist/cli/commands/sandbox.js +306 -0
- package/dist/cli.js +9 -0
- package/dist/sandbox/chat.d.ts +40 -0
- package/dist/sandbox/chat.js +280 -0
- package/dist/types.d.ts +81 -0
- package/package.json +6 -3
- package/src/api.ts +55 -1
- package/src/auth.ts +7 -2
- package/src/cli/commands/help.ts +10 -0
- package/src/cli/commands/sandbox.ts +365 -0
- package/src/cli.ts +11 -0
- package/src/sandbox/chat.ts +339 -0
- package/src/types.ts +98 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox Chat Utility Module
|
|
3
|
+
* Handles chat session management, message sending, and polling for responses
|
|
4
|
+
*/
|
|
5
|
+
import { randomBytes } from 'crypto';
|
|
6
|
+
import { listIntegrations, listConnectors, createSandboxPersona, createActor, sendChatMessage, getChatHistory } from '../api.js';
|
|
7
|
+
const SANDBOX_INTEGRATION_IDN = 'sandbox';
|
|
8
|
+
const DEFAULT_TIMEZONE = 'America/Los_Angeles';
|
|
9
|
+
const POLL_INTERVAL_MS = 1000; // 1 second
|
|
10
|
+
const MAX_POLL_ATTEMPTS = 60; // Max 60 seconds wait
|
|
11
|
+
/**
|
|
12
|
+
* Generate a random external ID for chat session
|
|
13
|
+
*/
|
|
14
|
+
function generateExternalId() {
|
|
15
|
+
return randomBytes(3).toString('hex');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate a unique persona name with NEWO CLI prefix
|
|
19
|
+
*/
|
|
20
|
+
function generatePersonaName() {
|
|
21
|
+
const guid = randomBytes(8).toString('hex');
|
|
22
|
+
return `newo-cli-${guid}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Find a sandbox connector from the customer's connectors list
|
|
26
|
+
*/
|
|
27
|
+
export async function findSandboxConnector(client, verbose = false) {
|
|
28
|
+
if (verbose)
|
|
29
|
+
console.log('🔍 Searching for sandbox integration...');
|
|
30
|
+
// First, get all integrations to find the sandbox integration
|
|
31
|
+
const integrations = await listIntegrations(client);
|
|
32
|
+
const sandboxIntegration = integrations.find(i => i.idn === SANDBOX_INTEGRATION_IDN);
|
|
33
|
+
if (!sandboxIntegration) {
|
|
34
|
+
if (verbose)
|
|
35
|
+
console.log('❌ Sandbox integration not found');
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
if (verbose)
|
|
39
|
+
console.log(`✓ Found sandbox integration: ${sandboxIntegration.id}`);
|
|
40
|
+
// Now get connectors for the sandbox integration
|
|
41
|
+
if (verbose)
|
|
42
|
+
console.log('🔍 Searching for sandbox connectors...');
|
|
43
|
+
const connectors = await listConnectors(client, sandboxIntegration.id);
|
|
44
|
+
const sandboxConnectors = connectors.filter(c => c.status === 'running');
|
|
45
|
+
if (sandboxConnectors.length === 0) {
|
|
46
|
+
if (verbose)
|
|
47
|
+
console.log('❌ No running sandbox connectors found');
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (verbose) {
|
|
51
|
+
console.log(`✓ Found ${sandboxConnectors.length} running sandbox connector(s)`);
|
|
52
|
+
const firstConnector = sandboxConnectors[0];
|
|
53
|
+
if (firstConnector) {
|
|
54
|
+
console.log(` Using: ${firstConnector.connector_idn}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return sandboxConnectors[0] || null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Create a new sandbox chat session
|
|
61
|
+
*/
|
|
62
|
+
export async function createChatSession(client, connector, verbose = false) {
|
|
63
|
+
const personaName = generatePersonaName();
|
|
64
|
+
const externalId = generateExternalId();
|
|
65
|
+
if (verbose)
|
|
66
|
+
console.log(`📝 Creating persona: ${personaName}`);
|
|
67
|
+
// Create user persona
|
|
68
|
+
const personaResponse = await createSandboxPersona(client, {
|
|
69
|
+
name: personaName,
|
|
70
|
+
title: personaName
|
|
71
|
+
});
|
|
72
|
+
if (verbose)
|
|
73
|
+
console.log(`✓ Persona created: ${personaResponse.id}`);
|
|
74
|
+
// Create actor (ties persona to sandbox connector)
|
|
75
|
+
if (verbose)
|
|
76
|
+
console.log(`🔗 Creating actor for ${connector.connector_idn}...`);
|
|
77
|
+
const actorResponse = await createActor(client, personaResponse.id, {
|
|
78
|
+
name: personaName,
|
|
79
|
+
external_id: externalId,
|
|
80
|
+
integration_idn: SANDBOX_INTEGRATION_IDN,
|
|
81
|
+
connector_idn: connector.connector_idn,
|
|
82
|
+
time_zone_identifier: DEFAULT_TIMEZONE
|
|
83
|
+
});
|
|
84
|
+
if (verbose)
|
|
85
|
+
console.log(`✓ Actor created: ${actorResponse.id} (Chat ID)`);
|
|
86
|
+
return {
|
|
87
|
+
user_persona_id: personaResponse.id,
|
|
88
|
+
user_actor_id: actorResponse.id,
|
|
89
|
+
agent_persona_id: null, // Will be populated from first response
|
|
90
|
+
connector_idn: connector.connector_idn,
|
|
91
|
+
session_id: null,
|
|
92
|
+
external_id: externalId
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Send a message in the chat session
|
|
97
|
+
* Returns the timestamp when message was sent (for filtering responses)
|
|
98
|
+
*/
|
|
99
|
+
export async function sendMessage(client, session, text, verbose = false) {
|
|
100
|
+
if (verbose)
|
|
101
|
+
console.log(`💬 Sending message: "${text}"`);
|
|
102
|
+
const sentAt = new Date();
|
|
103
|
+
await sendChatMessage(client, session.user_actor_id, {
|
|
104
|
+
text,
|
|
105
|
+
arguments: []
|
|
106
|
+
});
|
|
107
|
+
if (verbose)
|
|
108
|
+
console.log('✓ Message sent');
|
|
109
|
+
return sentAt;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Poll for new conversation acts (messages and debug info)
|
|
113
|
+
* Continues polling until we get an agent response, not just any new message
|
|
114
|
+
*/
|
|
115
|
+
export async function pollForResponse(client, session, messageSentAt = null, verbose = false) {
|
|
116
|
+
let attempts = 0;
|
|
117
|
+
let agentPersonaId = session.agent_persona_id;
|
|
118
|
+
if (verbose)
|
|
119
|
+
console.log('⏳ Waiting for agent response...');
|
|
120
|
+
// Add small delay before first poll to allow message to be processed
|
|
121
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
122
|
+
while (attempts < MAX_POLL_ATTEMPTS) {
|
|
123
|
+
try {
|
|
124
|
+
if (verbose && attempts % 5 === 0) {
|
|
125
|
+
console.log(` [Poll attempt ${attempts + 1}/${MAX_POLL_ATTEMPTS}] Checking for messages...`);
|
|
126
|
+
}
|
|
127
|
+
// Use Chat History API instead of acts API (doesn't require account_id)
|
|
128
|
+
const response = await getChatHistory(client, {
|
|
129
|
+
user_actor_id: session.user_actor_id,
|
|
130
|
+
page: 1,
|
|
131
|
+
per: 100
|
|
132
|
+
});
|
|
133
|
+
if (verbose && attempts === 0) {
|
|
134
|
+
console.log(` Initial poll returned ${response.items.length} message(s)`);
|
|
135
|
+
}
|
|
136
|
+
if (response.items && response.items.length > 0) {
|
|
137
|
+
// Convert chat history format to acts format
|
|
138
|
+
const convertedActs = response.items.map((item) => ({
|
|
139
|
+
id: item.id || `chat_${Math.random()}`,
|
|
140
|
+
command_act_id: null,
|
|
141
|
+
external_event_id: item.external_event_id || 'chat_history',
|
|
142
|
+
arguments: item.arguments || [],
|
|
143
|
+
reference_idn: (item.is_agent === true) ? 'agent_message' : 'user_message',
|
|
144
|
+
runtime_context_id: item.runtime_context_id || 'chat_history',
|
|
145
|
+
source_text: item.payload?.text || item.message || item.content || item.text || '',
|
|
146
|
+
original_text: item.payload?.text || item.message || item.content || item.text || '',
|
|
147
|
+
datetime: item.datetime || item.created_at || item.timestamp || new Date().toISOString(),
|
|
148
|
+
user_actor_id: session.user_actor_id,
|
|
149
|
+
agent_actor_id: item.agent_actor_id || null,
|
|
150
|
+
user_persona_id: session.user_persona_id,
|
|
151
|
+
user_persona_name: 'User',
|
|
152
|
+
agent_persona_id: item.agent_persona_id || agentPersonaId || 'unknown',
|
|
153
|
+
external_id: item.external_id || null,
|
|
154
|
+
integration_idn: 'sandbox',
|
|
155
|
+
connector_idn: session.connector_idn,
|
|
156
|
+
to_integration_idn: null,
|
|
157
|
+
to_connector_idn: null,
|
|
158
|
+
is_agent: Boolean(item.is_agent === true),
|
|
159
|
+
project_idn: item.project_idn || null,
|
|
160
|
+
flow_idn: item.flow_idn || 'unknown',
|
|
161
|
+
skill_idn: item.skill_idn || 'unknown',
|
|
162
|
+
session_id: item.session_id || session.session_id || 'unknown',
|
|
163
|
+
recordings: item.recordings || [],
|
|
164
|
+
contact_information: item.contact_information || null
|
|
165
|
+
}));
|
|
166
|
+
// Extract agent_persona_id from the first act if we don't have it yet
|
|
167
|
+
if (!agentPersonaId && convertedActs.length > 0) {
|
|
168
|
+
const firstItem = convertedActs[0];
|
|
169
|
+
if (firstItem && firstItem.agent_persona_id !== 'unknown') {
|
|
170
|
+
agentPersonaId = firstItem.agent_persona_id;
|
|
171
|
+
if (verbose)
|
|
172
|
+
console.log(`✓ Extracted agent_persona_id: ${agentPersonaId}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Filter for agent messages that came AFTER our message was sent
|
|
176
|
+
const agentMessages = convertedActs.filter(act => {
|
|
177
|
+
if (!act.is_agent)
|
|
178
|
+
return false;
|
|
179
|
+
// If we have a messageSentAt timestamp, ONLY include messages with datetime after it
|
|
180
|
+
if (messageSentAt) {
|
|
181
|
+
// Parse the act datetime - it may not have timezone, assume UTC
|
|
182
|
+
let actDatetime = act.datetime;
|
|
183
|
+
if (!actDatetime.endsWith('Z') && !actDatetime.includes('+') && !actDatetime.includes('-', 10)) {
|
|
184
|
+
actDatetime = actDatetime + 'Z'; // Assume UTC if no timezone
|
|
185
|
+
}
|
|
186
|
+
const actTime = new Date(actDatetime);
|
|
187
|
+
const sentTime = messageSentAt.getTime();
|
|
188
|
+
const actTimeMs = actTime.getTime();
|
|
189
|
+
const timeDiff = actTimeMs - sentTime;
|
|
190
|
+
if (verbose && attempts === 0) {
|
|
191
|
+
console.log(` Checking agent message:`);
|
|
192
|
+
console.log(` Original datetime: ${act.datetime}`);
|
|
193
|
+
console.log(` Parsed datetime: ${actDatetime}`);
|
|
194
|
+
console.log(` Act timestamp: ${actTimeMs} (${new Date(actTimeMs).toISOString()})`);
|
|
195
|
+
console.log(` Sent timestamp: ${sentTime} (${messageSentAt.toISOString()})`);
|
|
196
|
+
console.log(` Difference: ${timeDiff}ms (${(timeDiff / 1000).toFixed(1)}s)`);
|
|
197
|
+
console.log(` Include: ${timeDiff > -100 ? 'YES' : 'NO'}`);
|
|
198
|
+
}
|
|
199
|
+
// Only include messages sent AFTER our message (allow small negative buffer for processing time)
|
|
200
|
+
return timeDiff > -100;
|
|
201
|
+
}
|
|
202
|
+
// For first message (no messageSentAt), include all agent messages
|
|
203
|
+
return true;
|
|
204
|
+
});
|
|
205
|
+
if (agentMessages.length > 0) {
|
|
206
|
+
if (verbose)
|
|
207
|
+
console.log(`✓ Received ${agentMessages.length} agent message(s) after our message (${messageSentAt?.toISOString()})`);
|
|
208
|
+
// Return ONLY the single newest agent message (first one, since API returns newest first)
|
|
209
|
+
const latestAgentMessage = agentMessages[0];
|
|
210
|
+
if (latestAgentMessage) {
|
|
211
|
+
return { acts: [latestAgentMessage], agentPersonaId };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else if (verbose && attempts % 10 === 0) {
|
|
215
|
+
console.log(` No new agent messages yet (checked ${response.items.length} total messages, sentAt: ${messageSentAt?.toISOString()}), continuing...`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
if (verbose && attempts < 3) {
|
|
221
|
+
console.log(`⚠️ Error polling (attempt ${attempts + 1}): ${error.message}`);
|
|
222
|
+
}
|
|
223
|
+
// Continue polling despite errors
|
|
224
|
+
}
|
|
225
|
+
attempts++;
|
|
226
|
+
await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
227
|
+
}
|
|
228
|
+
if (verbose)
|
|
229
|
+
console.log('⏱️ Timeout waiting for response');
|
|
230
|
+
return { acts: [], agentPersonaId };
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Extract agent messages from acts
|
|
234
|
+
*/
|
|
235
|
+
export function extractAgentMessages(acts) {
|
|
236
|
+
return acts.filter(act => act.is_agent && act.reference_idn === 'agent_message');
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Extract debug information from acts
|
|
240
|
+
*/
|
|
241
|
+
export function extractDebugInfo(acts) {
|
|
242
|
+
return acts.map(act => ({
|
|
243
|
+
flow_idn: act.flow_idn,
|
|
244
|
+
skill_idn: act.skill_idn,
|
|
245
|
+
session_id: act.session_id,
|
|
246
|
+
runtime_context_id: act.runtime_context_id,
|
|
247
|
+
reference_idn: act.reference_idn,
|
|
248
|
+
arguments: act.arguments
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Format debug info for display
|
|
253
|
+
*/
|
|
254
|
+
export function formatDebugInfo(acts) {
|
|
255
|
+
const lines = [];
|
|
256
|
+
for (const act of acts) {
|
|
257
|
+
if (act.is_agent) {
|
|
258
|
+
lines.push(`\n[Agent Act] ${act.reference_idn}`);
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
lines.push(`\n[User Act] ${act.reference_idn}`);
|
|
262
|
+
}
|
|
263
|
+
lines.push(` Flow: ${act.flow_idn || 'N/A'}`);
|
|
264
|
+
lines.push(` Skill: ${act.skill_idn || 'N/A'}`);
|
|
265
|
+
lines.push(` Session: ${act.session_id}`);
|
|
266
|
+
if (act.runtime_context_id) {
|
|
267
|
+
lines.push(` Context: ${act.runtime_context_id}`);
|
|
268
|
+
}
|
|
269
|
+
if (act.arguments && act.arguments.length > 0) {
|
|
270
|
+
lines.push(` Arguments:`);
|
|
271
|
+
for (const arg of act.arguments) {
|
|
272
|
+
if (typeof arg === 'object' && arg !== null && 'name' in arg) {
|
|
273
|
+
lines.push(` ${arg.name}: ${JSON.stringify(arg.value).substring(0, 100)}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return lines.join('\n');
|
|
279
|
+
}
|
|
280
|
+
//# sourceMappingURL=chat.js.map
|
package/dist/types.d.ts
CHANGED
|
@@ -480,4 +480,85 @@ export interface PublishFlowRequest {
|
|
|
480
480
|
export interface PublishFlowResponse {
|
|
481
481
|
success: boolean;
|
|
482
482
|
}
|
|
483
|
+
export interface Integration {
|
|
484
|
+
readonly id: string;
|
|
485
|
+
readonly title: string;
|
|
486
|
+
readonly idn: string;
|
|
487
|
+
readonly description: string;
|
|
488
|
+
readonly is_disabled: boolean;
|
|
489
|
+
readonly channel: string;
|
|
490
|
+
}
|
|
491
|
+
export interface IntegrationSetting {
|
|
492
|
+
readonly title: string;
|
|
493
|
+
readonly idn: string;
|
|
494
|
+
readonly control_type: string;
|
|
495
|
+
readonly value_type: string;
|
|
496
|
+
readonly is_required: boolean;
|
|
497
|
+
readonly default_value?: string | null;
|
|
498
|
+
}
|
|
499
|
+
export interface Connector {
|
|
500
|
+
readonly id: string;
|
|
501
|
+
readonly title: string;
|
|
502
|
+
readonly connector_idn: string;
|
|
503
|
+
readonly integration_idn: string;
|
|
504
|
+
readonly status: string;
|
|
505
|
+
readonly api_key?: string;
|
|
506
|
+
readonly settings: readonly ConnectorSetting[];
|
|
507
|
+
}
|
|
508
|
+
export interface ConnectorSetting {
|
|
509
|
+
readonly idn: string;
|
|
510
|
+
readonly value: string;
|
|
511
|
+
}
|
|
512
|
+
export interface CreateSandboxPersonaRequest {
|
|
513
|
+
name: string;
|
|
514
|
+
title: string;
|
|
515
|
+
}
|
|
516
|
+
export interface CreateSandboxPersonaResponse {
|
|
517
|
+
id: string;
|
|
518
|
+
}
|
|
519
|
+
export interface CreateActorRequest {
|
|
520
|
+
name: string;
|
|
521
|
+
external_id: string;
|
|
522
|
+
integration_idn: string;
|
|
523
|
+
connector_idn: string;
|
|
524
|
+
time_zone_identifier?: string;
|
|
525
|
+
}
|
|
526
|
+
export interface CreateActorResponse {
|
|
527
|
+
id: string;
|
|
528
|
+
}
|
|
529
|
+
export interface SendChatMessageRequest {
|
|
530
|
+
text: string;
|
|
531
|
+
arguments?: readonly any[];
|
|
532
|
+
}
|
|
533
|
+
export interface ConversationActsParams {
|
|
534
|
+
user_persona_id: string;
|
|
535
|
+
user_actor_id: string;
|
|
536
|
+
agent_persona_id?: string;
|
|
537
|
+
per?: number;
|
|
538
|
+
page?: number;
|
|
539
|
+
}
|
|
540
|
+
export interface ConversationActsResponse {
|
|
541
|
+
readonly items: readonly ConversationAct[];
|
|
542
|
+
readonly metadata?: {
|
|
543
|
+
readonly page: number;
|
|
544
|
+
readonly per: number;
|
|
545
|
+
readonly total: number;
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
export interface SandboxChatSession {
|
|
549
|
+
user_persona_id: string;
|
|
550
|
+
user_actor_id: string;
|
|
551
|
+
agent_persona_id: string | null;
|
|
552
|
+
connector_idn: string;
|
|
553
|
+
session_id: string | null;
|
|
554
|
+
external_id: string;
|
|
555
|
+
}
|
|
556
|
+
export interface ChatDebugInfo {
|
|
557
|
+
flow_idn: string | null;
|
|
558
|
+
skill_idn: string | null;
|
|
559
|
+
session_id: string;
|
|
560
|
+
runtime_context_id: string | null;
|
|
561
|
+
reference_idn: string;
|
|
562
|
+
arguments: readonly any[];
|
|
563
|
+
}
|
|
483
564
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "newo",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "NEWO CLI: Professional command-line tool with modular architecture for NEWO AI Agent development. Features IDN-based file management, real-time progress tracking, intelligent sync operations, and comprehensive multi-customer support.",
|
|
3
|
+
"version": "3.1.0",
|
|
4
|
+
"description": "NEWO CLI: Professional command-line tool with modular architecture for NEWO AI Agent development. Features sandbox testing, IDN-based file management, real-time progress tracking, intelligent sync operations, and comprehensive multi-customer support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"newo": "dist/cli.js"
|
|
@@ -29,7 +29,10 @@
|
|
|
29
29
|
"workspace",
|
|
30
30
|
"conversations",
|
|
31
31
|
"chat-history",
|
|
32
|
-
"personas"
|
|
32
|
+
"personas",
|
|
33
|
+
"sandbox",
|
|
34
|
+
"testing",
|
|
35
|
+
"agent-testing"
|
|
33
36
|
],
|
|
34
37
|
"author": "sabbah13",
|
|
35
38
|
"license": "MIT",
|
package/src/api.ts
CHANGED
|
@@ -34,7 +34,16 @@ import type {
|
|
|
34
34
|
CreateProjectRequest,
|
|
35
35
|
CreateProjectResponse,
|
|
36
36
|
PublishFlowRequest,
|
|
37
|
-
PublishFlowResponse
|
|
37
|
+
PublishFlowResponse,
|
|
38
|
+
Integration,
|
|
39
|
+
Connector,
|
|
40
|
+
CreateSandboxPersonaRequest,
|
|
41
|
+
CreateSandboxPersonaResponse,
|
|
42
|
+
CreateActorRequest,
|
|
43
|
+
CreateActorResponse,
|
|
44
|
+
SendChatMessageRequest,
|
|
45
|
+
ConversationActsParams,
|
|
46
|
+
ConversationActsResponse
|
|
38
47
|
} from './types.js';
|
|
39
48
|
|
|
40
49
|
// Per-request retry tracking to avoid shared state issues
|
|
@@ -311,4 +320,49 @@ export async function createPersona(client: AxiosInstance, personaData: CreatePe
|
|
|
311
320
|
export async function publishFlow(client: AxiosInstance, flowId: string, publishData: PublishFlowRequest): Promise<PublishFlowResponse> {
|
|
312
321
|
const response = await client.post<PublishFlowResponse>(`/api/v1/designer/flows/${flowId}/publish`, publishData);
|
|
313
322
|
return response.data;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Sandbox Chat API Functions
|
|
326
|
+
|
|
327
|
+
export async function listIntegrations(client: AxiosInstance): Promise<Integration[]> {
|
|
328
|
+
const response = await client.get<Integration[]>('/api/v1/integrations');
|
|
329
|
+
return response.data;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export async function listConnectors(client: AxiosInstance, integrationId: string): Promise<Connector[]> {
|
|
333
|
+
const response = await client.get<Connector[]>(`/api/v1/integrations/${integrationId}/connectors`);
|
|
334
|
+
return response.data;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
export async function createSandboxPersona(client: AxiosInstance, personaData: CreateSandboxPersonaRequest): Promise<CreateSandboxPersonaResponse> {
|
|
338
|
+
const response = await client.post<CreateSandboxPersonaResponse>('/api/v1/customer/personas', personaData);
|
|
339
|
+
return response.data;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export async function createActor(client: AxiosInstance, personaId: string, actorData: CreateActorRequest): Promise<CreateActorResponse> {
|
|
343
|
+
const response = await client.post<CreateActorResponse>(`/api/v1/customer/personas/${personaId}/actors`, actorData);
|
|
344
|
+
return response.data;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export async function sendChatMessage(client: AxiosInstance, actorId: string, messageData: SendChatMessageRequest): Promise<void> {
|
|
348
|
+
await client.post(`/api/v1/chat/user/${actorId}`, messageData);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export async function getConversationActs(client: AxiosInstance, params: ConversationActsParams): Promise<ConversationActsResponse> {
|
|
352
|
+
const queryParams: Record<string, any> = {
|
|
353
|
+
user_persona_id: params.user_persona_id,
|
|
354
|
+
user_actor_id: params.user_actor_id,
|
|
355
|
+
per: params.per || 100,
|
|
356
|
+
page: params.page || 1
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// Only add agent_persona_id if provided
|
|
360
|
+
if (params.agent_persona_id) {
|
|
361
|
+
queryParams.agent_persona_id = params.agent_persona_id;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const response = await client.get<ConversationActsResponse>('/api/v1/bff/conversations/acts', {
|
|
365
|
+
params: queryParams
|
|
366
|
+
});
|
|
367
|
+
return response.data;
|
|
314
368
|
}
|
package/src/auth.ts
CHANGED
|
@@ -54,6 +54,11 @@ function validateUrl(url: string, name: string): void {
|
|
|
54
54
|
|
|
55
55
|
// Enhanced logging function
|
|
56
56
|
function logAuthEvent(level: 'info' | 'warn' | 'error', message: string, meta?: Record<string, unknown>): void {
|
|
57
|
+
// Skip all logging if in quiet mode
|
|
58
|
+
if (process.env.NEWO_QUIET_MODE === 'true') {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
57
62
|
const timestamp = new Date().toISOString();
|
|
58
63
|
const logEntry = {
|
|
59
64
|
timestamp,
|
|
@@ -62,7 +67,7 @@ function logAuthEvent(level: 'info' | 'warn' | 'error', message: string, meta?:
|
|
|
62
67
|
message,
|
|
63
68
|
...meta
|
|
64
69
|
};
|
|
65
|
-
|
|
70
|
+
|
|
66
71
|
// Sanitize sensitive data
|
|
67
72
|
const sanitized = JSON.parse(JSON.stringify(logEntry, (key, value) => {
|
|
68
73
|
if (typeof key === 'string' && (key.toLowerCase().includes('key') || key.toLowerCase().includes('token') || key.toLowerCase().includes('secret'))) {
|
|
@@ -70,7 +75,7 @@ function logAuthEvent(level: 'info' | 'warn' | 'error', message: string, meta?:
|
|
|
70
75
|
}
|
|
71
76
|
return value;
|
|
72
77
|
}));
|
|
73
|
-
|
|
78
|
+
|
|
74
79
|
if (level === 'error') {
|
|
75
80
|
console.error(JSON.stringify(sanitized));
|
|
76
81
|
} else if (level === 'warn') {
|
package/src/cli/commands/help.ts
CHANGED
|
@@ -11,6 +11,8 @@ Core Commands:
|
|
|
11
11
|
newo push [--customer <idn>] [--no-publish] # upload modified *.guidance/*.jinja + attributes back to NEWO, publish flows by default
|
|
12
12
|
newo status [--customer <idn>] # show modified files that would be pushed
|
|
13
13
|
newo conversations [--customer <idn>] [--all] # download user conversations -> ./newo_customers/<idn>/conversations.yaml
|
|
14
|
+
newo sandbox "<message>" [--customer <idn>] # test agent in sandbox - single message mode (NEW v3.1.0)
|
|
15
|
+
newo sandbox --actor <id> "message" # continue existing sandbox conversation with chat ID
|
|
14
16
|
newo pull-attributes [--customer <idn>] # download customer attributes -> ./newo_customers/<idn>/attributes.yaml
|
|
15
17
|
newo list-customers # list available customers and their configuration
|
|
16
18
|
newo meta [--customer <idn>] # get project metadata (debug command)
|
|
@@ -46,6 +48,8 @@ Flags:
|
|
|
46
48
|
--all # include all available data (for conversations: all personas and acts)
|
|
47
49
|
--force, -f # force overwrite without prompting (for pull command)
|
|
48
50
|
--verbose, -v # enable detailed logging and progress information
|
|
51
|
+
--quiet, -q # minimal output for automation (sandbox only)
|
|
52
|
+
--actor <id> # continue existing sandbox chat with actor/chat ID
|
|
49
53
|
--confirm # confirm destructive operations without prompting
|
|
50
54
|
--no-publish # skip automatic flow publishing during push operations
|
|
51
55
|
|
|
@@ -108,6 +112,12 @@ Usage Examples:
|
|
|
108
112
|
# Import AKB articles:
|
|
109
113
|
newo import-akb articles.txt da4550db-2b95-4500-91ff-fb4b60fe7be9
|
|
110
114
|
|
|
115
|
+
# Sandbox testing (NEW v3.1.0):
|
|
116
|
+
newo sandbox "Hello, I want to order pizza" # Start new conversation
|
|
117
|
+
newo sandbox --actor abc123... "I want 2 large pizzas" # Continue conversation
|
|
118
|
+
newo sandbox "Test query" --verbose # With debug info
|
|
119
|
+
newo sandbox "Test query" --quiet # For automation/scripts
|
|
120
|
+
|
|
111
121
|
File Structure:
|
|
112
122
|
newo_customers/
|
|
113
123
|
├── <customer-idn>/
|