newo 1.7.3 → 1.9.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 +61 -0
- package/dist/api.d.ts +9 -1
- package/dist/api.js +50 -0
- package/dist/cli.js +50 -1
- package/dist/fsutil.d.ts +1 -0
- package/dist/fsutil.js +3 -0
- package/dist/sync.d.ts +2 -1
- package/dist/sync.js +545 -26
- package/dist/types.d.ts +118 -0
- package/package.json +8 -3
- package/src/api.ts +63 -1
- package/src/cli.ts +50 -1
- package/src/fsutil.ts +4 -0
- package/src/sync.ts +627 -27
- package/src/types.ts +132 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,67 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.9.0] - 2025-09-16
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **User Conversations Pull Functionality**: Complete conversation history extraction
|
|
12
|
+
- New `newo conversations` command to download user conversations and personas
|
|
13
|
+
- Multi-customer conversation support with `--customer <idn>` flag
|
|
14
|
+
- Chat History API integration (`/api/v1/chat/history`) with fallback to conversations acts API
|
|
15
|
+
- Automatic phone number extraction from persona actors
|
|
16
|
+
- Comprehensive pagination handling for large conversation datasets
|
|
17
|
+
- Clean YAML output format in `newo_customers/{customerIdn}/conversations.yaml`
|
|
18
|
+
|
|
19
|
+
### Enhanced
|
|
20
|
+
- **Conversation Data Processing**: Optimized structure and chronological ordering
|
|
21
|
+
- Acts sorted by datetime ascending (chronological conversation flow)
|
|
22
|
+
- Personas sorted by most recent activity (descending)
|
|
23
|
+
- Redundant fields removed (`is_agent`, `session_id: unknown`, etc.)
|
|
24
|
+
- Clean persona structure: `id` → `name` → `phone` → `act_count` → `acts`
|
|
25
|
+
- Proper datetime extraction from chat history API responses
|
|
26
|
+
|
|
27
|
+
### Technical
|
|
28
|
+
- **New API Functions**: Type-safe conversation API integration
|
|
29
|
+
- `listUserPersonas()` - Get all user personas with pagination
|
|
30
|
+
- `getChatHistory()` - Get conversation history for user actors
|
|
31
|
+
- `getConversationActs()` - Fallback for accounts with proper permissions
|
|
32
|
+
- `pullConversations()` - Complete conversation sync orchestration
|
|
33
|
+
- **NPM Scripts**: Added convenient conversation commands
|
|
34
|
+
- `npm run conversations` - Build and pull conversations
|
|
35
|
+
- `npm run conversations:all` - Legacy alias for compatibility
|
|
36
|
+
|
|
37
|
+
### Performance
|
|
38
|
+
- **Concurrent Processing**: Efficient conversation data extraction
|
|
39
|
+
- Parallel API calls with concurrency limiting (p-limit)
|
|
40
|
+
- Graceful error handling with persona-level fault tolerance
|
|
41
|
+
- No artificial limits on personas or acts (loads all available data)
|
|
42
|
+
- Multi-customer support with authentication reuse
|
|
43
|
+
|
|
44
|
+
## [1.8.0] - 2025-09-15
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
- **Complete Metadata Change Tracking**: Comprehensive metadata.yaml file synchronization
|
|
48
|
+
- All metadata.yaml files now tracked with hash-based change detection
|
|
49
|
+
- Status command shows detailed metadata changes (title, runner_type, model)
|
|
50
|
+
- Push command automatically updates skills when metadata changes
|
|
51
|
+
- flows.yaml automatically regenerated when metadata changes detected
|
|
52
|
+
- Preserves flows.yaml format consistency with backup/comparison system
|
|
53
|
+
|
|
54
|
+
### Enhanced
|
|
55
|
+
- **Comprehensive File Synchronization**: All NEWO workspace files fully tracked
|
|
56
|
+
- Skills: .guidance and .jinja script files with hash tracking ✓
|
|
57
|
+
- Metadata: metadata.yaml files with skill updates + flows.yaml regeneration ✓
|
|
58
|
+
- Attributes: attributes.yaml with diff-based sync for 233 customer attributes ✓
|
|
59
|
+
- Flows: flows.yaml with automatic regeneration and format preservation ✓
|
|
60
|
+
- Multi-customer: All file types synchronized across multiple customer workspaces ✓
|
|
61
|
+
|
|
62
|
+
### Technical
|
|
63
|
+
- **flows.yaml Regeneration**: Automatic regeneration pipeline when metadata changes
|
|
64
|
+
- Creates backup before regeneration for format comparison
|
|
65
|
+
- Re-fetches project data to ensure accuracy
|
|
66
|
+
- Updates hash tracking for regenerated flows.yaml
|
|
67
|
+
- Maintains consistent YAML format structure
|
|
68
|
+
|
|
8
69
|
## [1.7.3] - 2025-09-15
|
|
9
70
|
|
|
10
71
|
### Added
|
package/dist/api.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AxiosInstance } from 'axios';
|
|
2
|
-
import type { ProjectMeta, Agent, Skill, FlowEvent, FlowState, AkbImportArticle, CustomerProfile, CustomerAttribute, CustomerAttributesResponse } from './types.js';
|
|
2
|
+
import type { ProjectMeta, Agent, Skill, FlowEvent, FlowState, AkbImportArticle, CustomerProfile, CustomerAttribute, CustomerAttributesResponse, UserPersonaResponse, UserPersona, ConversationActsResponse, ConversationActsParams, ChatHistoryParams, ChatHistoryResponse } from './types.js';
|
|
3
3
|
export declare function makeClient(verbose?: boolean, token?: string): Promise<AxiosInstance>;
|
|
4
4
|
export declare function listProjects(client: AxiosInstance): Promise<ProjectMeta[]>;
|
|
5
5
|
export declare function listAgents(client: AxiosInstance, projectId: string): Promise<Agent[]>;
|
|
@@ -13,4 +13,12 @@ export declare function importAkbArticle(client: AxiosInstance, articleData: Akb
|
|
|
13
13
|
export declare function getCustomerProfile(client: AxiosInstance): Promise<CustomerProfile>;
|
|
14
14
|
export declare function getCustomerAttributes(client: AxiosInstance, includeHidden?: boolean): Promise<CustomerAttributesResponse>;
|
|
15
15
|
export declare function updateCustomerAttribute(client: AxiosInstance, attribute: CustomerAttribute): Promise<void>;
|
|
16
|
+
export declare function listUserPersonas(client: AxiosInstance, page?: number, per?: number): Promise<UserPersonaResponse>;
|
|
17
|
+
export declare function getUserPersona(client: AxiosInstance, personaId: string): Promise<UserPersona>;
|
|
18
|
+
export declare function getAccount(client: AxiosInstance): Promise<{
|
|
19
|
+
id: string;
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}>;
|
|
22
|
+
export declare function getConversationActs(client: AxiosInstance, params: ConversationActsParams): Promise<ConversationActsResponse>;
|
|
23
|
+
export declare function getChatHistory(client: AxiosInstance, params: ChatHistoryParams): Promise<ChatHistoryResponse>;
|
|
16
24
|
//# sourceMappingURL=api.d.ts.map
|
package/dist/api.js
CHANGED
|
@@ -121,4 +121,54 @@ export async function updateCustomerAttribute(client, attribute) {
|
|
|
121
121
|
value_type: attribute.value_type
|
|
122
122
|
});
|
|
123
123
|
}
|
|
124
|
+
// Conversation API Functions
|
|
125
|
+
export async function listUserPersonas(client, page = 1, per = 50) {
|
|
126
|
+
const response = await client.get('/api/v1/bff/conversations/user-personas', {
|
|
127
|
+
params: { page, per }
|
|
128
|
+
});
|
|
129
|
+
return response.data;
|
|
130
|
+
}
|
|
131
|
+
export async function getUserPersona(client, personaId) {
|
|
132
|
+
const response = await client.get(`/api/v1/bff/conversations/user-personas/${personaId}`);
|
|
133
|
+
return response.data;
|
|
134
|
+
}
|
|
135
|
+
export async function getAccount(client) {
|
|
136
|
+
const response = await client.get('/api/v1/account');
|
|
137
|
+
return response.data;
|
|
138
|
+
}
|
|
139
|
+
export async function getConversationActs(client, params) {
|
|
140
|
+
const queryParams = {
|
|
141
|
+
user_persona_id: params.user_persona_id,
|
|
142
|
+
page: params.page || 1,
|
|
143
|
+
per: params.per || 50
|
|
144
|
+
};
|
|
145
|
+
// Only add optional parameters if explicitly provided
|
|
146
|
+
if (params.turn_type)
|
|
147
|
+
queryParams.turn_type = params.turn_type;
|
|
148
|
+
if (params.connectors)
|
|
149
|
+
queryParams.connectors = params.connectors;
|
|
150
|
+
if (params.from_date)
|
|
151
|
+
queryParams.from_date = params.from_date;
|
|
152
|
+
if (params.to_date)
|
|
153
|
+
queryParams.to_date = params.to_date;
|
|
154
|
+
const response = await client.get('/api/v1/bff/conversations/acts', {
|
|
155
|
+
params: queryParams
|
|
156
|
+
});
|
|
157
|
+
return response.data;
|
|
158
|
+
}
|
|
159
|
+
export async function getChatHistory(client, params) {
|
|
160
|
+
const queryParams = {
|
|
161
|
+
user_actor_id: params.user_actor_id,
|
|
162
|
+
page: params.page || 1,
|
|
163
|
+
per: params.per || 50
|
|
164
|
+
};
|
|
165
|
+
// Only add agent_actor_id if provided
|
|
166
|
+
if (params.agent_actor_id) {
|
|
167
|
+
queryParams.agent_actor_id = params.agent_actor_id;
|
|
168
|
+
}
|
|
169
|
+
const response = await client.get('/api/v1/chat/history', {
|
|
170
|
+
params: queryParams
|
|
171
|
+
});
|
|
172
|
+
return response.data;
|
|
173
|
+
}
|
|
124
174
|
//# sourceMappingURL=api.js.map
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import minimist from 'minimist';
|
|
3
3
|
import dotenv from 'dotenv';
|
|
4
4
|
import { makeClient, getProjectMeta, importAkbArticle } from './api.js';
|
|
5
|
-
import { pullAll, pushChanged, status, saveCustomerAttributes } from './sync.js';
|
|
5
|
+
import { pullAll, pushChanged, status, saveCustomerAttributes, pullConversations } from './sync.js';
|
|
6
6
|
import { parseAkbFile, prepareArticlesForImport } from './akb.js';
|
|
7
7
|
import { initializeEnvironment, ENV, EnvValidationError } from './env.js';
|
|
8
8
|
import { parseCustomerConfigAsync, listCustomers, getCustomer, getDefaultCustomer, tryGetDefaultCustomer, getAllCustomers, validateCustomerConfig } from './customerAsync.js';
|
|
@@ -160,12 +160,14 @@ Usage:
|
|
|
160
160
|
newo pull [--customer <idn>] # download projects -> ./newo_customers/<idn>/projects/
|
|
161
161
|
newo push [--customer <idn>] # upload modified *.guidance/*.jinja back to NEWO
|
|
162
162
|
newo status [--customer <idn>] # show modified files
|
|
163
|
+
newo conversations [--customer <idn>] [--all] # download user conversations -> ./newo_customers/<idn>/conversations.yaml
|
|
163
164
|
newo list-customers # list available customers
|
|
164
165
|
newo meta [--customer <idn>] # get project metadata (debug)
|
|
165
166
|
newo import-akb <file> <persona_id> [--customer <idn>] # import AKB articles from file
|
|
166
167
|
|
|
167
168
|
Flags:
|
|
168
169
|
--customer <idn> # specify customer (if not set, uses default or interactive selection)
|
|
170
|
+
--all # include all available data (for conversations: all personas and acts)
|
|
169
171
|
--verbose, -v # enable detailed logging
|
|
170
172
|
|
|
171
173
|
Environment Variables:
|
|
@@ -343,6 +345,53 @@ File Structure:
|
|
|
343
345
|
}
|
|
344
346
|
return;
|
|
345
347
|
}
|
|
348
|
+
if (cmd === 'conversations') {
|
|
349
|
+
// Handle customer selection for conversations command
|
|
350
|
+
if (args.customer) {
|
|
351
|
+
const customer = getCustomer(customerConfig, args.customer);
|
|
352
|
+
if (!customer) {
|
|
353
|
+
console.error(`Unknown customer: ${args.customer}`);
|
|
354
|
+
console.error(`Available customers: ${listCustomers(customerConfig).join(', ')}`);
|
|
355
|
+
process.exit(1);
|
|
356
|
+
}
|
|
357
|
+
selectedCustomer = customer;
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
// Try to get default, fall back to all customers
|
|
361
|
+
selectedCustomer = tryGetDefaultCustomer(customerConfig);
|
|
362
|
+
if (!selectedCustomer) {
|
|
363
|
+
allCustomers = getAllCustomers(customerConfig);
|
|
364
|
+
if (verbose)
|
|
365
|
+
console.log(`💬 No default customer specified, pulling conversations from all ${allCustomers.length} customers`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// Parse conversation-specific options - load all data by default
|
|
369
|
+
const conversationOptions = {
|
|
370
|
+
includeAll: true, // Always include all data for conversations
|
|
371
|
+
maxPersonas: undefined, // No limit on personas
|
|
372
|
+
maxActsPerPersona: undefined // No limit on acts per persona
|
|
373
|
+
};
|
|
374
|
+
if (selectedCustomer) {
|
|
375
|
+
// Single customer conversations
|
|
376
|
+
const accessToken = await getValidAccessToken(selectedCustomer);
|
|
377
|
+
const client = await makeClient(verbose, accessToken);
|
|
378
|
+
console.log(`💬 Pulling conversations for customer: ${selectedCustomer.idn} (all data)`);
|
|
379
|
+
await pullConversations(client, selectedCustomer, conversationOptions, verbose);
|
|
380
|
+
console.log(`✅ Conversations saved to newo_customers/${selectedCustomer.idn}/conversations.yaml`);
|
|
381
|
+
}
|
|
382
|
+
else if (allCustomers.length > 0) {
|
|
383
|
+
// Multi-customer conversations
|
|
384
|
+
console.log(`💬 Pulling conversations from ${allCustomers.length} customers (all data)...`);
|
|
385
|
+
for (const customer of allCustomers) {
|
|
386
|
+
console.log(`\n💬 Pulling conversations for customer: ${customer.idn}`);
|
|
387
|
+
const accessToken = await getValidAccessToken(customer);
|
|
388
|
+
const client = await makeClient(verbose, accessToken);
|
|
389
|
+
await pullConversations(client, customer, conversationOptions, verbose);
|
|
390
|
+
}
|
|
391
|
+
console.log(`\n✅ Conversations pull completed for all ${allCustomers.length} customers`);
|
|
392
|
+
}
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
346
395
|
// For all other commands, require a single selected customer
|
|
347
396
|
if (args.customer) {
|
|
348
397
|
const customer = getCustomer(customerConfig, args.customer);
|
package/dist/fsutil.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare function projectDir(customerIdn: string, projectIdn: string): str
|
|
|
11
11
|
export declare function flowsYamlPath(customerIdn: string): string;
|
|
12
12
|
export declare function customerAttributesPath(customerIdn: string): string;
|
|
13
13
|
export declare function customerAttributesMapPath(customerIdn: string): string;
|
|
14
|
+
export declare function customerAttributesBackupPath(customerIdn: string): string;
|
|
14
15
|
export declare function skillPath(customerIdn: string, projectIdn: string, agentIdn: string, flowIdn: string, skillIdn: string, runnerType?: RunnerType): string;
|
|
15
16
|
export declare function skillFolderPath(customerIdn: string, projectIdn: string, agentIdn: string, flowIdn: string, skillIdn: string): string;
|
|
16
17
|
export declare function skillScriptPath(customerIdn: string, projectIdn: string, agentIdn: string, flowIdn: string, skillIdn: string, runnerType?: RunnerType): string;
|
package/dist/fsutil.js
CHANGED
|
@@ -34,6 +34,9 @@ export function customerAttributesPath(customerIdn) {
|
|
|
34
34
|
export function customerAttributesMapPath(customerIdn) {
|
|
35
35
|
return path.join(customerStateDir(customerIdn), 'attributes-map.json');
|
|
36
36
|
}
|
|
37
|
+
export function customerAttributesBackupPath(customerIdn) {
|
|
38
|
+
return path.join(customerStateDir(customerIdn), 'attributes-backup.yaml');
|
|
39
|
+
}
|
|
37
40
|
// Legacy skill path - direct file
|
|
38
41
|
export function skillPath(customerIdn, projectIdn, agentIdn, flowIdn, skillIdn, runnerType = 'guidance') {
|
|
39
42
|
const extension = runnerType === 'nsl' ? '.jinja' : '.guidance';
|
package/dist/sync.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { AxiosInstance } from 'axios';
|
|
2
|
-
import type { ProjectData, CustomerConfig } from './types.js';
|
|
2
|
+
import type { ProjectData, CustomerConfig, ConversationOptions } from './types.js';
|
|
3
3
|
export declare function saveCustomerAttributes(client: AxiosInstance, customer: CustomerConfig, verbose?: boolean): Promise<void>;
|
|
4
4
|
export declare function pullSingleProject(client: AxiosInstance, customer: CustomerConfig, projectId: string, projectIdn: string, verbose?: boolean): Promise<ProjectData>;
|
|
5
5
|
export declare function pullAll(client: AxiosInstance, customer: CustomerConfig, projectId?: string | null, verbose?: boolean): Promise<void>;
|
|
6
6
|
export declare function pushChanged(client: AxiosInstance, customer: CustomerConfig, verbose?: boolean): Promise<void>;
|
|
7
7
|
export declare function status(customer: CustomerConfig, verbose?: boolean): Promise<void>;
|
|
8
|
+
export declare function pullConversations(client: AxiosInstance, customer: CustomerConfig, options?: ConversationOptions, verbose?: boolean): Promise<void>;
|
|
8
9
|
//# sourceMappingURL=sync.d.ts.map
|