@higher.archi/boe 1.0.27 → 1.0.29
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/engines/decay/compiler.d.ts +11 -0
- package/dist/engines/decay/compiler.d.ts.map +1 -0
- package/dist/engines/decay/compiler.js +216 -0
- package/dist/engines/decay/compiler.js.map +1 -0
- package/dist/engines/decay/engine.d.ts +79 -0
- package/dist/engines/decay/engine.d.ts.map +1 -0
- package/dist/engines/decay/engine.js +159 -0
- package/dist/engines/decay/engine.js.map +1 -0
- package/dist/engines/decay/index.d.ts +9 -0
- package/dist/engines/decay/index.d.ts.map +1 -0
- package/dist/engines/decay/index.js +21 -0
- package/dist/engines/decay/index.js.map +1 -0
- package/dist/engines/decay/strategy.d.ts +21 -0
- package/dist/engines/decay/strategy.d.ts.map +1 -0
- package/dist/engines/decay/strategy.js +308 -0
- package/dist/engines/decay/strategy.js.map +1 -0
- package/dist/engines/decay/types.d.ts +157 -0
- package/dist/engines/decay/types.d.ts.map +1 -0
- package/dist/engines/decay/types.js +39 -0
- package/dist/engines/decay/types.js.map +1 -0
- package/dist/engines/negotiation/compiler.d.ts +11 -0
- package/dist/engines/negotiation/compiler.d.ts.map +1 -0
- package/dist/engines/negotiation/compiler.js +177 -0
- package/dist/engines/negotiation/compiler.js.map +1 -0
- package/dist/engines/negotiation/engine.d.ts +46 -0
- package/dist/engines/negotiation/engine.d.ts.map +1 -0
- package/dist/engines/negotiation/engine.js +88 -0
- package/dist/engines/negotiation/engine.js.map +1 -0
- package/dist/engines/negotiation/index.d.ts +8 -0
- package/dist/engines/negotiation/index.d.ts.map +1 -0
- package/dist/engines/negotiation/index.js +17 -0
- package/dist/engines/negotiation/index.js.map +1 -0
- package/dist/engines/negotiation/strategy.d.ts +18 -0
- package/dist/engines/negotiation/strategy.d.ts.map +1 -0
- package/dist/engines/negotiation/strategy.js +439 -0
- package/dist/engines/negotiation/strategy.js.map +1 -0
- package/dist/engines/negotiation/types.d.ts +179 -0
- package/dist/engines/negotiation/types.d.ts.map +1 -0
- package/dist/engines/negotiation/types.js +10 -0
- package/dist/engines/negotiation/types.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/engines/decay/compiler.ts +276 -0
- package/src/engines/decay/engine.ts +211 -0
- package/src/engines/decay/index.ts +43 -0
- package/src/engines/decay/strategy.ts +433 -0
- package/src/engines/decay/types.ts +231 -0
- package/src/engines/negotiation/compiler.ts +229 -0
- package/src/engines/negotiation/engine.ts +117 -0
- package/src/engines/negotiation/index.ts +42 -0
- package/src/engines/negotiation/strategy.ts +587 -0
- package/src/engines/negotiation/types.ts +244 -0
- package/src/index.ts +69 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Negotiation Engine Compiler
|
|
3
|
+
*
|
|
4
|
+
* Validates negotiation rulesets and resolves defaults.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { CompilationError } from '../../core/errors';
|
|
8
|
+
import { SEMANTIC_PRIORITY_VALUES, isSemanticPriority, type SemanticPriority } from '../utility/types';
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
NegotiationRuleSet,
|
|
12
|
+
CompiledNegotiationRuleSet,
|
|
13
|
+
CompiledZopaAnalysisRuleSet,
|
|
14
|
+
CompiledConcessionPlanningRuleSet,
|
|
15
|
+
CompiledPackageOptimizationRuleSet,
|
|
16
|
+
CompiledValueFunction,
|
|
17
|
+
CompiledPartyProfile,
|
|
18
|
+
ValueFunction
|
|
19
|
+
} from './types';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Compile and validate a negotiation ruleset.
|
|
23
|
+
*/
|
|
24
|
+
export function compileNegotiationRuleSet(
|
|
25
|
+
ruleSet: NegotiationRuleSet
|
|
26
|
+
): CompiledNegotiationRuleSet {
|
|
27
|
+
if (!ruleSet.id) {
|
|
28
|
+
throw new CompilationError('Negotiation ruleset requires an id');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (ruleSet.mode !== 'negotiation') {
|
|
32
|
+
throw new CompilationError(`Expected mode 'negotiation', got '${ruleSet.mode}'`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Validate dimensions
|
|
36
|
+
if (!ruleSet.dimensions || ruleSet.dimensions.length === 0) {
|
|
37
|
+
throw new CompilationError('At least one dimension is required');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const dimensionIds = new Set<string>();
|
|
41
|
+
for (const dim of ruleSet.dimensions) {
|
|
42
|
+
if (!dim.id) {
|
|
43
|
+
throw new CompilationError('Each dimension requires an id');
|
|
44
|
+
}
|
|
45
|
+
if (dimensionIds.has(dim.id)) {
|
|
46
|
+
throw new CompilationError(`Duplicate dimension id: '${dim.id}'`);
|
|
47
|
+
}
|
|
48
|
+
dimensionIds.add(dim.id);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Validate exactly 2 parties
|
|
52
|
+
if (!ruleSet.parties || ruleSet.parties.length !== 2) {
|
|
53
|
+
throw new CompilationError('Exactly 2 parties are required');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Validate party positions reference existing dimensions and ordering
|
|
57
|
+
for (const party of ruleSet.parties) {
|
|
58
|
+
if (!party.id) {
|
|
59
|
+
throw new CompilationError('Each party requires an id');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const pos of party.positions) {
|
|
63
|
+
if (!dimensionIds.has(pos.dimensionId)) {
|
|
64
|
+
throw new CompilationError(
|
|
65
|
+
`Party '${party.id}' references unknown dimension '${pos.dimensionId}'`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Validate acceptable is between ideal and walkaway
|
|
70
|
+
// Each party can have any direction preference -- the dimension direction
|
|
71
|
+
// represents party A's preference, party B naturally has the opposite.
|
|
72
|
+
const minVal = Math.min(pos.ideal, pos.walkaway);
|
|
73
|
+
const maxVal = Math.max(pos.ideal, pos.walkaway);
|
|
74
|
+
if (pos.acceptable < minVal || pos.acceptable > maxVal) {
|
|
75
|
+
throw new CompilationError(
|
|
76
|
+
`Party '${party.id}', dimension '${pos.dimensionId}': ` +
|
|
77
|
+
`acceptable must be between ideal and walkaway`
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
if (pos.ideal === pos.walkaway) {
|
|
81
|
+
throw new CompilationError(
|
|
82
|
+
`Party '${party.id}', dimension '${pos.dimensionId}': ` +
|
|
83
|
+
`ideal and walkaway must differ`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Resolve and normalize value weights per party
|
|
90
|
+
const compiledWeights: Record<string, CompiledValueFunction[]> = {};
|
|
91
|
+
|
|
92
|
+
for (const partyId of Object.keys(ruleSet.valueWeights)) {
|
|
93
|
+
const weights = ruleSet.valueWeights[partyId];
|
|
94
|
+
const resolved = resolveWeights(weights, partyId);
|
|
95
|
+
compiledWeights[partyId] = resolved;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Build compiled parties
|
|
99
|
+
const compiledParties: [CompiledPartyProfile, CompiledPartyProfile] = [
|
|
100
|
+
{
|
|
101
|
+
id: ruleSet.parties[0].id,
|
|
102
|
+
name: ruleSet.parties[0].name,
|
|
103
|
+
positions: ruleSet.parties[0].positions,
|
|
104
|
+
batna: ruleSet.parties[0].batna
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: ruleSet.parties[1].id,
|
|
108
|
+
name: ruleSet.parties[1].name,
|
|
109
|
+
positions: ruleSet.parties[1].positions,
|
|
110
|
+
batna: ruleSet.parties[1].batna
|
|
111
|
+
}
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
switch (ruleSet.strategy) {
|
|
115
|
+
case 'zopa-analysis':
|
|
116
|
+
return compileZopaAnalysis(ruleSet, compiledParties, compiledWeights);
|
|
117
|
+
case 'concession-planning':
|
|
118
|
+
return compileConcessionPlanning(ruleSet, compiledParties, compiledWeights);
|
|
119
|
+
case 'package-optimization':
|
|
120
|
+
return compilePackageOptimization(ruleSet, compiledParties, compiledWeights);
|
|
121
|
+
default:
|
|
122
|
+
throw new CompilationError(`Unknown negotiation strategy: '${(ruleSet as any).strategy}'`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ========================================
|
|
127
|
+
// Strategy-Specific Compilers
|
|
128
|
+
// ========================================
|
|
129
|
+
|
|
130
|
+
function compileZopaAnalysis(
|
|
131
|
+
ruleSet: NegotiationRuleSet & { strategy: 'zopa-analysis' },
|
|
132
|
+
parties: [CompiledPartyProfile, CompiledPartyProfile],
|
|
133
|
+
valueWeights: Record<string, CompiledValueFunction[]>
|
|
134
|
+
): CompiledZopaAnalysisRuleSet {
|
|
135
|
+
return {
|
|
136
|
+
id: ruleSet.id,
|
|
137
|
+
name: ruleSet.name,
|
|
138
|
+
mode: 'negotiation',
|
|
139
|
+
strategy: 'zopa-analysis',
|
|
140
|
+
dimensions: ruleSet.dimensions,
|
|
141
|
+
parties,
|
|
142
|
+
valueWeights,
|
|
143
|
+
config: {
|
|
144
|
+
resolution: ruleSet.config?.resolution ?? 100
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function compileConcessionPlanning(
|
|
150
|
+
ruleSet: NegotiationRuleSet & { strategy: 'concession-planning' },
|
|
151
|
+
parties: [CompiledPartyProfile, CompiledPartyProfile],
|
|
152
|
+
valueWeights: Record<string, CompiledValueFunction[]>
|
|
153
|
+
): CompiledConcessionPlanningRuleSet {
|
|
154
|
+
return {
|
|
155
|
+
id: ruleSet.id,
|
|
156
|
+
name: ruleSet.name,
|
|
157
|
+
mode: 'negotiation',
|
|
158
|
+
strategy: 'concession-planning',
|
|
159
|
+
dimensions: ruleSet.dimensions,
|
|
160
|
+
parties,
|
|
161
|
+
valueWeights,
|
|
162
|
+
config: {
|
|
163
|
+
style: ruleSet.config?.style ?? 'moderate',
|
|
164
|
+
rounds: ruleSet.config?.rounds ?? 5,
|
|
165
|
+
startingPosition: ruleSet.config?.startingPosition ?? 'ideal'
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function compilePackageOptimization(
|
|
171
|
+
ruleSet: NegotiationRuleSet & { strategy: 'package-optimization' },
|
|
172
|
+
parties: [CompiledPartyProfile, CompiledPartyProfile],
|
|
173
|
+
valueWeights: Record<string, CompiledValueFunction[]>
|
|
174
|
+
): CompiledPackageOptimizationRuleSet {
|
|
175
|
+
return {
|
|
176
|
+
id: ruleSet.id,
|
|
177
|
+
name: ruleSet.name,
|
|
178
|
+
mode: 'negotiation',
|
|
179
|
+
strategy: 'package-optimization',
|
|
180
|
+
dimensions: ruleSet.dimensions,
|
|
181
|
+
parties,
|
|
182
|
+
valueWeights,
|
|
183
|
+
config: {
|
|
184
|
+
sampleSize: ruleSet.config?.sampleSize ?? 1000,
|
|
185
|
+
objectiveWeights: ruleSet.config?.objectiveWeights ?? {
|
|
186
|
+
closeProb: 0.6,
|
|
187
|
+
margin: 0.4
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ========================================
|
|
194
|
+
// Weight Resolution
|
|
195
|
+
// ========================================
|
|
196
|
+
|
|
197
|
+
function resolveWeights(
|
|
198
|
+
weights: ValueFunction[],
|
|
199
|
+
partyId: string
|
|
200
|
+
): CompiledValueFunction[] {
|
|
201
|
+
const resolved: CompiledValueFunction[] = weights.map(w => {
|
|
202
|
+
let weight: number;
|
|
203
|
+
if (isSemanticPriority(w.weight)) {
|
|
204
|
+
weight = SEMANTIC_PRIORITY_VALUES[w.weight as SemanticPriority];
|
|
205
|
+
} else if (typeof w.weight === 'number') {
|
|
206
|
+
weight = w.weight;
|
|
207
|
+
} else {
|
|
208
|
+
throw new CompilationError(
|
|
209
|
+
`Invalid weight for party '${partyId}', dimension '${w.dimensionId}': '${w.weight}'`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
dimensionId: w.dimensionId,
|
|
215
|
+
weight
|
|
216
|
+
};
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// Normalize to sum to 1.0
|
|
220
|
+
const totalWeight = resolved.reduce((sum, w) => sum + w.weight, 0);
|
|
221
|
+
if (totalWeight === 0) {
|
|
222
|
+
throw new CompilationError(`Value weights for party '${partyId}' must not all be zero`);
|
|
223
|
+
}
|
|
224
|
+
for (const w of resolved) {
|
|
225
|
+
w.weight = w.weight / totalWeight;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return resolved;
|
|
229
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Negotiation Engine
|
|
3
|
+
*
|
|
4
|
+
* Two-party negotiation engine that analyzes zones of possible agreement,
|
|
5
|
+
* plans concession strategies, and optimizes deal packages across
|
|
6
|
+
* multiple dimensions.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const engine = new NegotiationEngine();
|
|
11
|
+
*
|
|
12
|
+
* const result = engine.execute(compiledNegotiation);
|
|
13
|
+
* console.log(result.outcome); // 'agreed' | 'no-zopa' | 'batna-preferred'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
WorkingMemory,
|
|
19
|
+
Fact,
|
|
20
|
+
FactInput,
|
|
21
|
+
FactChange
|
|
22
|
+
} from '../../core';
|
|
23
|
+
|
|
24
|
+
import type {
|
|
25
|
+
CompiledNegotiationRuleSet,
|
|
26
|
+
NegotiationOptions,
|
|
27
|
+
NegotiationResult
|
|
28
|
+
} from './types';
|
|
29
|
+
|
|
30
|
+
import { NegotiationExecutor } from './strategy';
|
|
31
|
+
|
|
32
|
+
export class NegotiationEngine {
|
|
33
|
+
private wm: WorkingMemory;
|
|
34
|
+
private strategy: NegotiationExecutor;
|
|
35
|
+
|
|
36
|
+
constructor(workingMemory?: WorkingMemory) {
|
|
37
|
+
this.wm = workingMemory ?? new WorkingMemory();
|
|
38
|
+
this.strategy = new NegotiationExecutor();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ========================================
|
|
42
|
+
// IWorkingMemory Implementation
|
|
43
|
+
// ========================================
|
|
44
|
+
|
|
45
|
+
add<T = Record<string, any>>(input: FactInput<T>): Fact<T> {
|
|
46
|
+
return this.wm.add(input);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
remove(factId: string): Fact | undefined {
|
|
50
|
+
return this.wm.remove(factId);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
update<T = Record<string, any>>(input: FactInput<T>): Fact<T> {
|
|
54
|
+
return this.wm.update(input);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get(factId: string): Fact | undefined {
|
|
58
|
+
return this.wm.get(factId);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getByType(type: string): Fact[] {
|
|
62
|
+
return this.wm.getByType(type);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getAll(): Fact[] {
|
|
66
|
+
return this.wm.getAll();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
has(factId: string): boolean {
|
|
70
|
+
return this.wm.has(factId);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
size(): number {
|
|
74
|
+
return this.wm.size();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
clear(): void {
|
|
78
|
+
this.wm.clear();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
getChanges(): FactChange[] {
|
|
82
|
+
return this.wm.getChanges();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
clearChanges(): void {
|
|
86
|
+
this.wm.clearChanges();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ========================================
|
|
90
|
+
// Engine Execution
|
|
91
|
+
// ========================================
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Execute a negotiation ruleset.
|
|
95
|
+
*
|
|
96
|
+
* Analyzes party positions across all dimensions and produces
|
|
97
|
+
* a negotiation result with ZOPA, concession plans, or optimized packages.
|
|
98
|
+
*
|
|
99
|
+
* @param ruleSet - Compiled negotiation ruleset
|
|
100
|
+
* @param options - Runtime options (onStep callback, onPackage callback)
|
|
101
|
+
* @returns Negotiation result with outcome and analysis
|
|
102
|
+
*/
|
|
103
|
+
execute(
|
|
104
|
+
ruleSet: CompiledNegotiationRuleSet,
|
|
105
|
+
options: NegotiationOptions = {}
|
|
106
|
+
): NegotiationResult {
|
|
107
|
+
return this.strategy.run(ruleSet, options);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ========================================
|
|
111
|
+
// Utility Methods
|
|
112
|
+
// ========================================
|
|
113
|
+
|
|
114
|
+
getWorkingMemory(): WorkingMemory {
|
|
115
|
+
return this.wm;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Negotiation Engine -- Two-Party Deal Analysis
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Types
|
|
6
|
+
export type {
|
|
7
|
+
NegotiationStrategy,
|
|
8
|
+
ConcessionStyle,
|
|
9
|
+
DealOutcome,
|
|
10
|
+
DimensionDirection,
|
|
11
|
+
NegotiationDimension,
|
|
12
|
+
PartyPosition,
|
|
13
|
+
PartyProfile,
|
|
14
|
+
ValueFunction,
|
|
15
|
+
CompiledValueFunction,
|
|
16
|
+
CompiledPartyProfile,
|
|
17
|
+
ZopaAnalysisConfig,
|
|
18
|
+
ConcessionPlanningConfig,
|
|
19
|
+
PackageOptimizationConfig,
|
|
20
|
+
ZopaAnalysisRuleSet,
|
|
21
|
+
ConcessionPlanningRuleSet,
|
|
22
|
+
PackageOptimizationRuleSet,
|
|
23
|
+
NegotiationRuleSet,
|
|
24
|
+
CompiledZopaAnalysisRuleSet,
|
|
25
|
+
CompiledConcessionPlanningRuleSet,
|
|
26
|
+
CompiledPackageOptimizationRuleSet,
|
|
27
|
+
CompiledNegotiationRuleSet,
|
|
28
|
+
ZopaRange,
|
|
29
|
+
ConcessionStep,
|
|
30
|
+
PackageCandidate,
|
|
31
|
+
NegotiationResult,
|
|
32
|
+
NegotiationOptions
|
|
33
|
+
} from './types';
|
|
34
|
+
|
|
35
|
+
// Compiler
|
|
36
|
+
export { compileNegotiationRuleSet } from './compiler';
|
|
37
|
+
|
|
38
|
+
// Strategy
|
|
39
|
+
export { NegotiationExecutor, negotiationStrategy } from './strategy';
|
|
40
|
+
|
|
41
|
+
// Engine
|
|
42
|
+
export { NegotiationEngine } from './engine';
|