@llm-dev-ops/agentics-cli 1.7.0 → 1.7.2
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/pipeline/auto-chain.d.ts.map +1 -1
- package/dist/pipeline/auto-chain.js +91 -3
- package/dist/pipeline/auto-chain.js.map +1 -1
- package/dist/pipeline/phase2/phases/research-dossier.d.ts.map +1 -1
- package/dist/pipeline/phase2/phases/research-dossier.js +19 -9
- package/dist/pipeline/phase2/phases/research-dossier.js.map +1 -1
- package/dist/synthesis/ask-artifact-writer.d.ts.map +1 -1
- package/dist/synthesis/ask-artifact-writer.js +25 -0
- package/dist/synthesis/ask-artifact-writer.js.map +1 -1
- package/dist/synthesis/simulation-renderers.d.ts.map +1 -1
- package/dist/synthesis/simulation-renderers.js +173 -36
- package/dist/synthesis/simulation-renderers.js.map +1 -1
- package/package.json +1 -1
|
@@ -251,24 +251,62 @@ function estimateFinancialsFromQuery(query) {
|
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
|
-
// Industry affects per-employee costs
|
|
254
|
+
// Industry affects per-employee costs and savings multiplier
|
|
255
255
|
const isPharma = lower.includes('pharma') || lower.includes('drug') || lower.includes('gxp') || lower.includes('clinical');
|
|
256
256
|
const isFinancial = lower.includes('financial') || lower.includes('banking') || lower.includes('insurance');
|
|
257
257
|
const isRetail = lower.includes('retail') || lower.includes('grocery') || lower.includes('store');
|
|
258
|
-
const
|
|
259
|
-
const
|
|
258
|
+
const isUtility = lower.includes('water') || lower.includes('utility') || lower.includes('energy') || lower.includes('grid') || lower.includes('distribution');
|
|
259
|
+
const isSustainability = lower.includes('sustainability') || lower.includes('emissions') || lower.includes('carbon') || lower.includes('esg');
|
|
260
|
+
const isHealthcare = lower.includes('healthcare') || lower.includes('hospital') || lower.includes('clinical') || lower.includes('patient');
|
|
261
|
+
const isProfessionalServices = lower.includes('professional services') || lower.includes('consulting') || lower.includes('advisory');
|
|
262
|
+
let industryLabel = 'enterprise';
|
|
263
|
+
let costPerEmployee = 25;
|
|
264
|
+
let savingsMultiplier = 50;
|
|
265
|
+
if (isPharma) {
|
|
266
|
+
costPerEmployee = 35;
|
|
267
|
+
savingsMultiplier = 80;
|
|
268
|
+
industryLabel = 'pharmaceutical';
|
|
269
|
+
}
|
|
270
|
+
else if (isFinancial) {
|
|
271
|
+
costPerEmployee = 30;
|
|
272
|
+
savingsMultiplier = 60;
|
|
273
|
+
industryLabel = 'financial services';
|
|
274
|
+
}
|
|
275
|
+
else if (isRetail) {
|
|
276
|
+
costPerEmployee = 15;
|
|
277
|
+
savingsMultiplier = 40;
|
|
278
|
+
industryLabel = 'retail';
|
|
279
|
+
}
|
|
280
|
+
else if (isUtility) {
|
|
281
|
+
costPerEmployee = 20;
|
|
282
|
+
savingsMultiplier = 55;
|
|
283
|
+
industryLabel = 'utility';
|
|
284
|
+
}
|
|
285
|
+
else if (isHealthcare) {
|
|
286
|
+
costPerEmployee = 30;
|
|
287
|
+
savingsMultiplier = 65;
|
|
288
|
+
industryLabel = 'healthcare';
|
|
289
|
+
}
|
|
290
|
+
else if (isSustainability || isProfessionalServices) {
|
|
291
|
+
costPerEmployee = 25;
|
|
292
|
+
savingsMultiplier = 50;
|
|
293
|
+
industryLabel = isSustainability ? 'sustainability' : 'professional services';
|
|
294
|
+
}
|
|
260
295
|
const pilotCost = Math.round(employees * costPerEmployee / 1000) * 1000;
|
|
261
296
|
const annualSavings = Math.round(employees * savingsMultiplier / 1000) * 1000;
|
|
262
297
|
const paybackMonths = Math.max(6, Math.min(24, Math.round(pilotCost / (annualSavings / 12))));
|
|
263
298
|
const npv5yr = Math.round(annualSavings * 3.5); // ~10% discount rate, 5 years
|
|
264
299
|
const roiPct = Math.round((annualSavings / pilotCost) * 100);
|
|
265
300
|
const fmt = (n) => n >= 1_000_000 ? `$${(n / 1_000_000).toFixed(1)}M` : `$${(n / 1000).toFixed(0)}K`;
|
|
301
|
+
// Build methodology string so the numbers are defensible
|
|
302
|
+
const methodology = `${employees.toLocaleString()} employees × $${costPerEmployee}/employee ${industryLabel} benchmark`;
|
|
303
|
+
const savingsMethod = `${employees.toLocaleString()} employees × $${savingsMultiplier}/employee annual efficiency gain`;
|
|
266
304
|
return {
|
|
267
|
-
budget: `${fmt(pilotCost)} - ${fmt(pilotCost * 1.5)} (
|
|
268
|
-
roi: `${roiPct}% projected (
|
|
269
|
-
npv: `${fmt(npv5yr)} 5-year NPV (
|
|
270
|
-
payback: `${paybackMonths}-${paybackMonths + 6} months (
|
|
271
|
-
revenue: `${fmt(annualSavings)} annual efficiency gains (
|
|
305
|
+
budget: `${fmt(pilotCost)} - ${fmt(pilotCost * 1.5)} (${methodology})`,
|
|
306
|
+
roi: `${roiPct}% projected (${fmt(annualSavings)} savings ÷ ${fmt(pilotCost)} investment)`,
|
|
307
|
+
npv: `${fmt(npv5yr)} 5-year NPV (10% discount rate, ${savingsMethod})`,
|
|
308
|
+
payback: `${paybackMonths}-${paybackMonths + 6} months (break-even when cumulative savings exceed investment)`,
|
|
309
|
+
revenue: `${fmt(annualSavings)} annual efficiency gains (${savingsMethod})`,
|
|
272
310
|
costSavings: '',
|
|
273
311
|
hasData: true,
|
|
274
312
|
isEstimated: true,
|
|
@@ -325,17 +363,58 @@ function generateDomainRisks(query, extracted) {
|
|
|
325
363
|
const q = query.toLowerCase();
|
|
326
364
|
const systems = extracted.systems;
|
|
327
365
|
const primarySystem = systems[0] ?? 'enterprise platform';
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
366
|
+
// System-specific data quality risks (not generic)
|
|
367
|
+
const isWorkday = /workday/i.test(q);
|
|
368
|
+
const isSAP = /sap|s\/4hana/i.test(q);
|
|
369
|
+
const isMaximo = /maximo|ibm/i.test(q);
|
|
370
|
+
if (isWorkday) {
|
|
371
|
+
risks.push({
|
|
372
|
+
risk: `Workday custom report and RaaS API data may have field-level gaps — expense categories, cost centers, and worker location data are often inconsistent across regions`,
|
|
373
|
+
category: 'Data', likelihood: 'High', impact: 'Medium', score: 6,
|
|
374
|
+
mitigation: 'Map required fields per Workday module (Expenses, Absence, Worker) during discovery; build validation for missing cost center and location codes',
|
|
375
|
+
});
|
|
376
|
+
risks.push({
|
|
377
|
+
risk: `Workday API rate limits (currently 10 req/sec for RaaS, 20 req/sec for REST) may constrain data sync for ${extracted.stakeholders.length > 2 ? 'large employee populations' : 'batch operations'}`,
|
|
378
|
+
category: 'Technical', likelihood: 'Medium', impact: 'High', score: 6,
|
|
379
|
+
mitigation: 'Implement incremental sync with delta queries; cache frequently accessed worker profiles; use Workday Integration Cloud for bulk data',
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
else if (isSAP) {
|
|
383
|
+
risks.push({
|
|
384
|
+
risk: `SAP S/4HANA OData API field mappings differ between on-premise and cloud editions — custom fields may not be accessible via standard APIs`,
|
|
385
|
+
category: 'Data', likelihood: 'High', impact: 'Medium', score: 6,
|
|
386
|
+
mitigation: 'Validate API access for each required field during technical spike; plan CDS view development for custom field exposure if needed',
|
|
387
|
+
});
|
|
388
|
+
risks.push({
|
|
389
|
+
risk: `SAP API authentication (OAuth2 + X-CSRF tokens) and transport security requirements add integration complexity`,
|
|
390
|
+
category: 'Technical', likelihood: 'Medium', impact: 'High', score: 6,
|
|
391
|
+
mitigation: 'Technical spike with SAP Basis team to validate API configuration; use SAP BTP Integration Suite if direct API access is restricted',
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
else if (isMaximo) {
|
|
395
|
+
risks.push({
|
|
396
|
+
risk: `IBM Maximo OSLC API may not expose all required asset and maintenance fields — custom attributes require explicit OSLC resource definition`,
|
|
397
|
+
category: 'Data', likelihood: 'High', impact: 'Medium', score: 6,
|
|
398
|
+
mitigation: 'Audit Maximo OSLC resource definitions during discovery; validate custom field availability via test queries against staging environment',
|
|
399
|
+
});
|
|
400
|
+
risks.push({
|
|
401
|
+
risk: `Maximo 7.x vs. MAS 8.x OSLC API differences — work order status transitions and custom field schemas differ between versions`,
|
|
402
|
+
category: 'Technical', likelihood: 'Medium', impact: 'High', score: 6,
|
|
403
|
+
mitigation: 'Confirm Maximo version and OSLC API version during technical spike; build version-aware adapter with feature detection',
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
risks.push({
|
|
408
|
+
risk: `Data quality and completeness in ${primarySystem} may not meet analytical requirements`,
|
|
409
|
+
category: 'Data', likelihood: 'High', impact: 'Medium', score: 6,
|
|
410
|
+
mitigation: 'Data profiling during discovery phase; validation layer with quarantine for invalid records',
|
|
411
|
+
});
|
|
412
|
+
risks.push({
|
|
413
|
+
risk: `${primarySystem} API integration complexity — rate limits, schema changes, authentication`,
|
|
414
|
+
category: 'Technical', likelihood: 'Medium', impact: 'High', score: 6,
|
|
415
|
+
mitigation: `Technical spike to validate ${primarySystem} API capabilities before full commitment`,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
339
418
|
risks.push({
|
|
340
419
|
risk: 'Scope creep beyond initial prototype boundaries',
|
|
341
420
|
category: 'Project', likelihood: 'High', impact: 'Medium', score: 6,
|
|
@@ -357,12 +436,32 @@ function generateDomainRisks(query, extracted) {
|
|
|
357
436
|
mitigation: 'Legal review per jurisdiction during discovery; configurable compliance rules per region',
|
|
358
437
|
});
|
|
359
438
|
}
|
|
360
|
-
// Sustainability risks
|
|
439
|
+
// Sustainability / emissions risks
|
|
361
440
|
if (/(?:emission|carbon|sustainab|environmental|energy|waste|esg)/i.test(q)) {
|
|
362
441
|
risks.push({
|
|
363
|
-
risk: 'Emissions factor accuracy — default factors may not match specific operational context',
|
|
442
|
+
risk: 'Emissions factor accuracy — DEFRA/EPA default factors may not match specific operational context (e.g., regional grid mix, fleet composition)',
|
|
364
443
|
category: 'Data', likelihood: 'Medium', impact: 'Medium', score: 4,
|
|
365
|
-
mitigation: 'Allow
|
|
444
|
+
mitigation: 'Allow organization-specific factors with audit trail; flag calculations using default vs. measured values; annual factor review process',
|
|
445
|
+
});
|
|
446
|
+
if (/travel|commut|flight|transport/i.test(q)) {
|
|
447
|
+
risks.push({
|
|
448
|
+
risk: 'Employee behavior change resistance — sustainability nudges may be perceived as restrictive or intrusive by frequent travelers',
|
|
449
|
+
category: 'Organizational', likelihood: 'Medium', impact: 'Medium', score: 4,
|
|
450
|
+
mitigation: 'Frame as insights, not mandates; gamification and positive reinforcement; executive sponsorship for culture shift',
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// Water/utility-specific risks
|
|
455
|
+
if (/(?:water|pipe|leak|pressure|distribution|meter|flow)/i.test(q)) {
|
|
456
|
+
risks.push({
|
|
457
|
+
risk: 'Sensor data gaps — pressure and flow telemetry may have coverage holes in older distribution zones with limited SCADA instrumentation',
|
|
458
|
+
category: 'Data', likelihood: 'High', impact: 'Medium', score: 6,
|
|
459
|
+
mitigation: 'Map sensor coverage per DMA during discovery; define minimum instrumentation requirements for analysis zones',
|
|
460
|
+
});
|
|
461
|
+
risks.push({
|
|
462
|
+
risk: 'Infrastructure intervention timelines — pipe replacement and pressure management projects require permitting and construction windows that may extend beyond prototype evaluation period',
|
|
463
|
+
category: 'Operational', likelihood: 'Medium', impact: 'Medium', score: 4,
|
|
464
|
+
mitigation: 'Focus prototype on detection and prioritization; track intervention recommendations separately from execution timelines',
|
|
366
465
|
});
|
|
367
466
|
}
|
|
368
467
|
// Financial risks
|
|
@@ -429,11 +528,16 @@ export function renderExecutiveSummary(query, simulationResult, platformResults)
|
|
|
429
528
|
lines.push(`Projected impact: ${impactParts.join(', ')}.`);
|
|
430
529
|
}
|
|
431
530
|
}
|
|
432
|
-
// ADR-PIPELINE-025 §4: Success probability with decomposition
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const
|
|
436
|
-
const
|
|
531
|
+
// ADR-PIPELINE-025 §4: Success probability with domain-aware decomposition
|
|
532
|
+
// Technical feasibility is higher (standard APIs/patterns), organizational readiness is lower
|
|
533
|
+
// for large workforces, data availability depends on ERP maturity, integration depends on system count
|
|
534
|
+
const hasLargeWorkforce = extracted.stakeholders.length > 3 || query.length > 800;
|
|
535
|
+
const hasMultipleSystems = extracted.systems.length > 1;
|
|
536
|
+
const hasComplexConstraints = extracted.constraints.length > 2;
|
|
537
|
+
const techFeasibility = Math.min(0.95, successProb + (hasMultipleSystems ? 0.02 : 0.06));
|
|
538
|
+
const orgReadiness = Math.max(0.65, successProb - (hasLargeWorkforce ? 0.08 : 0.03) - (hasComplexConstraints ? 0.03 : 0));
|
|
539
|
+
const dataAvailability = Math.max(0.70, successProb - (hasMultipleSystems ? 0.04 : 0.01));
|
|
540
|
+
const integrationFeasibility = Math.max(0.70, successProb - (extracted.systems.length * 0.02));
|
|
437
541
|
lines.push(`Success probability: **${(successProb * 100).toFixed(0)}%** (Technical ${(techFeasibility * 100).toFixed(0)}%, Organizational ${(orgReadiness * 100).toFixed(0)}%, Data ${(dataAvailability * 100).toFixed(0)}%, Integration ${(integrationFeasibility * 100).toFixed(0)}%) | Timeline: ${timeline}`, '');
|
|
438
542
|
// The Opportunity — cost of inaction
|
|
439
543
|
lines.push('## The Opportunity', '');
|
|
@@ -558,11 +662,21 @@ export function renderDecisionMemo(query, simulationResult, platformResults) {
|
|
|
558
662
|
'## Options Considered', '',
|
|
559
663
|
'| Option | Description | Investment | Timeline | Risk Level | Recommendation |',
|
|
560
664
|
'|--------|-------------|-----------|----------|------------|---------------|',
|
|
561
|
-
`| **A. Scoped Pilot** | Validate with subset of data and ${extracted.domain_entities.slice(0, 2).join(', ') || 'core entities'} | ${fin.budget || 'TBD'} (pilot scope) | 8-12 weeks | Low | **Recommended** |`,
|
|
562
|
-
`| **B. Full Deployment** | Enterprise-wide rollout across all ${extracted.systems.length > 0 ? extracted.systems.join(', ') : 'systems'} | ${fin.budget || 'TBD'} | ${safeString(simData, 'timeline_estimate') || '16-24 weeks'} | Medium | After pilot validation |`,
|
|
563
|
-
`| **C. Do Nothing** | Continue with manual processes | $0 | N/A | High | Not recommended — costs compound |`,
|
|
564
|
-
'',
|
|
565
665
|
];
|
|
666
|
+
// Compute pilot cost as ~30% of full deployment
|
|
667
|
+
const fullBudget = fin.budget || 'TBD';
|
|
668
|
+
let pilotBudget = fullBudget;
|
|
669
|
+
const budgetNum = fin.budget?.match(/\$([0-9,.]+)([KMB]?)/i);
|
|
670
|
+
if (budgetNum) {
|
|
671
|
+
const num = parseFloat(budgetNum[1].replace(/,/g, ''));
|
|
672
|
+
const suffix = (budgetNum[2] || '').toUpperCase();
|
|
673
|
+
const mult = suffix === 'M' ? 1_000_000 : suffix === 'K' ? 1_000 : suffix === 'B' ? 1_000_000_000 : 1;
|
|
674
|
+
const fullVal = num * mult;
|
|
675
|
+
const pilotVal = fullVal * 0.3;
|
|
676
|
+
const fmt = (n) => n >= 1_000_000 ? `$${(n / 1_000_000).toFixed(1)}M` : `$${(n / 1000).toFixed(0)}K`;
|
|
677
|
+
pilotBudget = `${fmt(pilotVal)} - ${fmt(pilotVal * 1.5)}`;
|
|
678
|
+
}
|
|
679
|
+
lines.push(`| **A. Scoped Pilot** | Validate with subset of data and ${extracted.domain_entities.slice(0, 2).join(', ') || 'core entities'} | ${pilotBudget} | 8-12 weeks | Low | **Recommended** |`, `| **B. Full Deployment** | Enterprise-wide rollout across all ${extracted.systems.length > 0 ? extracted.systems.join(', ') : 'systems'} | ${fullBudget} | ${safeString(simData, 'timeline_estimate') || '16-24 weeks'} | Medium | After pilot validation |`, `| **C. Do Nothing** | Continue with manual processes | $0 | N/A | High | Not recommended — costs compound |`, '');
|
|
566
680
|
// Financial Impact
|
|
567
681
|
lines.push('## Financial Impact', '');
|
|
568
682
|
if (fin.hasData) {
|
|
@@ -1007,28 +1121,51 @@ function extractScenarioFromQuery(query) {
|
|
|
1007
1121
|
* capitalizes the first word, and truncates to a readable length.
|
|
1008
1122
|
*/
|
|
1009
1123
|
function distillProblemStatement(query) {
|
|
1010
|
-
// Remove common preambles
|
|
1124
|
+
// Remove common preambles and context-setting openings
|
|
1011
1125
|
let cleaned = query
|
|
1126
|
+
// Strip "I lead/manage/run..." biographical introductions
|
|
1127
|
+
.replace(/^I\s+(?:lead|manage|run|oversee|am responsible for|work in|head)\s+[^.]+\.\s*/i, '')
|
|
1128
|
+
// Strip "We are a..." / "Our company is..." organizational descriptions
|
|
1129
|
+
.replace(/^(?:We are|Our (?:company|organization|firm|team) is)\s+[^.]+\.\s*/i, '')
|
|
1130
|
+
// Strip "One of the challenges..." problem setup
|
|
1131
|
+
.replace(/^One of the (?:challenges|issues|problems)\s+(?:we face|I face)\s+is\s+/i, '')
|
|
1132
|
+
// Strip standard intent preambles
|
|
1012
1133
|
.replace(/^(?:I want to|I'd like to|I need to|We need to|We want to|Please|Can you|Could you)\s+/i, '')
|
|
1013
1134
|
.replace(/^(?:build|create|design|develop|implement|generate|make)\s+(?:a\s+|an\s+)?/i, '')
|
|
1014
1135
|
.replace(/^(?:working\s+)?prototype\s+(?:for|of|that)\s+/i, '')
|
|
1015
1136
|
.replace(/^(?:proof of concept|poc)\s+(?:for|of|that)\s+/i, '')
|
|
1016
1137
|
.trim();
|
|
1138
|
+
// If the remaining text still starts with a lowercase conjunction or context word,
|
|
1139
|
+
// try to find the first real problem/goal sentence
|
|
1140
|
+
if (/^(right now|currently|at present|today|however|but|while|although)/i.test(cleaned)) {
|
|
1141
|
+
// Skip the context sentence and find the next one
|
|
1142
|
+
const nextSentence = cleaned.replace(/^[^.]+\.\s*/, '');
|
|
1143
|
+
if (nextSentence.length > 30)
|
|
1144
|
+
cleaned = nextSentence;
|
|
1145
|
+
}
|
|
1146
|
+
// Try to extract the core objective from "We believe..." / "Ideally..." / "The system would..."
|
|
1147
|
+
const idealMatch = query.match(/(?:we believe|ideally|the system (?:would|should)|the goal is|the objective is)\s+(.{30,200}?)(?:\.|$)/i);
|
|
1148
|
+
if (idealMatch && idealMatch[1] && cleaned.length > 200) {
|
|
1149
|
+
cleaned = idealMatch[1].trim();
|
|
1150
|
+
}
|
|
1017
1151
|
// Capitalize first letter
|
|
1018
1152
|
if (cleaned.length > 0) {
|
|
1019
1153
|
cleaned = cleaned[0].toUpperCase() + cleaned.slice(1);
|
|
1020
1154
|
}
|
|
1021
1155
|
// Truncate at sentence boundary if too long
|
|
1022
|
-
if (cleaned.length >
|
|
1023
|
-
const boundary = cleaned.lastIndexOf('.',
|
|
1156
|
+
if (cleaned.length > 150) {
|
|
1157
|
+
const boundary = cleaned.lastIndexOf('.', 150);
|
|
1024
1158
|
if (boundary > 40) {
|
|
1025
1159
|
cleaned = cleaned.slice(0, boundary + 1);
|
|
1026
1160
|
}
|
|
1027
1161
|
else {
|
|
1028
|
-
|
|
1162
|
+
// Truncate at last word boundary
|
|
1163
|
+
const truncated = cleaned.slice(0, 150);
|
|
1164
|
+
const lastSpace = truncated.lastIndexOf(' ');
|
|
1165
|
+
cleaned = (lastSpace > 100 ? truncated.slice(0, lastSpace) : truncated).trim();
|
|
1029
1166
|
}
|
|
1030
1167
|
}
|
|
1031
|
-
return cleaned || query.slice(0,
|
|
1168
|
+
return cleaned || query.slice(0, 150);
|
|
1032
1169
|
}
|
|
1033
1170
|
/**
|
|
1034
1171
|
* Synthesize agent response data into readable prose bullet points.
|