Index: opponentmodel/src/main/java/geniusweb/opponentmodel/FrequencyOpponentModel.java
===================================================================
--- opponentmodel/src/main/java/geniusweb/opponentmodel/FrequencyOpponentModel.java	(revision 14)
+++ opponentmodel/src/main/java/geniusweb/opponentmodel/FrequencyOpponentModel.java	(revision 18)
@@ -6,4 +6,6 @@
 import java.util.stream.Collectors;
 
+import geniusweb.actions.Action;
+import geniusweb.actions.Offer;
 import geniusweb.issuevalue.Bid;
 import geniusweb.issuevalue.Domain;
@@ -12,4 +14,5 @@
 import geniusweb.profile.utilityspace.NumberValueSetUtilities;
 import geniusweb.profile.utilityspace.UtilitySpace;
+import geniusweb.progress.Progress;
 
 /**
@@ -23,5 +26,5 @@
  *
  */
-public class FrequencyOpponentModel implements OpponentModel, UtilitySpace {
+public class FrequencyOpponentModel implements UtilitySpace, OpponentModel {
 
 	private static final int DECIMALS = 4; // accuracy of our computations.
@@ -32,5 +35,9 @@
 
 	public FrequencyOpponentModel(Domain domain) {
-		// map with empth hashmap for each issue.
+		/*
+		 * simply reset the whole model and make a new one... maybe this can be
+		 * done smarter for minor changes? map with empth hashmap for each
+		 * issue.
+		 */
 		this(domain,
 				domain.getIssues().stream().collect(
@@ -39,4 +46,26 @@
 	}
 
+	/**
+	 * internal constructor. Assumes the freqs keyset is equal to the available
+	 * issues.
+	 * 
+	 * @param domain the domain
+	 * @param freqs  the observed frequencies for all issue values. This map is
+	 *               assumed to be a fresh private-access only copy.
+	 * @param total  the total number of bids contained in the freqs map. This
+	 *               must be equal to the sum of the Integer values in the
+	 *               {@link #bidFrequencies} for each issue (this is not
+	 *               checked).
+	 */
+	private FrequencyOpponentModel(Domain domain,
+			Map<String, Map<Value, Integer>> freqs, BigDecimal total) {
+		if (domain == null) {
+			throw new NullPointerException("domain=null");
+		}
+		this.domain = domain;
+		this.bidFrequencies = freqs;
+		this.totalBids = total;
+	}
+
 	@Override
 	public BigDecimal getUtility(Bid bid) {
@@ -86,6 +115,16 @@
 	}
 
-	@Override
-	public FrequencyOpponentModel update(Bid bid) {
+	/**
+	 * {@inheritDoc}
+	 * 
+	 * <h1>change info</h1> This replaces update(Bid). Now you pass the entire
+	 * action and the progress instead of just the bid.
+	 */
+	@Override
+	public FrequencyOpponentModel with(Action action, Progress progress) {
+		if (!(action instanceof Offer))
+			return this;
+
+		Bid bid = ((Offer) action).getBid();
 		String err = domain.isComplete(bid);
 		if (err != null) {
@@ -108,26 +147,4 @@
 
 	/**
-	 * internal constructor. Assumes the freqs keyset is equal to the available
-	 * issues.
-	 * 
-	 * @param domain the domain
-	 * @param freqs  the observed frequencies for all issue values. This map is
-	 *               assumed to be a fresh private-access only copy.
-	 * @param total  the total number of bids contained in the freqs map. This
-	 *               must be equal to the sum of the Integer values in the
-	 *               {@link #bidFrequencies} for each issue (this is not
-	 *               checked).
-	 */
-	private FrequencyOpponentModel(Domain domain,
-			Map<String, Map<Value, Integer>> freqs, BigDecimal total) {
-		if (domain == null) {
-			throw new NullPointerException("domain=null");
-		}
-		this.domain = domain;
-		this.bidFrequencies = freqs;
-		this.totalBids = total;
-	}
-
-	/**
 	 * 
 	 * @param freqs
@@ -141,4 +158,10 @@
 		}
 		return map;
+	}
+
+	@Override
+	public Bid getReservationBid() {
+		// don't throw but we really have no clue.
+		return new Bid(new HashMap<>());
 	}
 
@@ -188,8 +211,3 @@
 	}
 
-	@Override
-	public Bid getReservationBid() {
-		throw new UnsupportedOperationException();
-	}
-
 }
Index: opponentmodel/src/main/java/geniusweb/opponentmodel/OpponentModel.java
===================================================================
--- opponentmodel/src/main/java/geniusweb/opponentmodel/OpponentModel.java	(revision 14)
+++ opponentmodel/src/main/java/geniusweb/opponentmodel/OpponentModel.java	(revision 18)
@@ -1,19 +1,30 @@
 package geniusweb.opponentmodel;
 
-import geniusweb.issuevalue.Bid;
+import geniusweb.actions.Action;
+import geniusweb.issuevalue.Domain;
 import geniusweb.profile.Profile;
 import geniusweb.profile.utilityspace.UtilitySpace;
+import geniusweb.progress.Progress;
 
 /**
  * An opponentmodel estimates a {@link UtilitySpace} from received opponent
- * bids.
+ * actions.
+ * <h1>Requirement</h1> A OpponentModel must have a constructor that takes the
+ * Domain as argument. unfortunately this can not be enforced in a java
+ * interface
  */
 public interface OpponentModel extends Profile {
+
 	/**
-	 *
-	 * @param bid the next bid that was received
-	 * @return a new {@link OpponentModel} that takes the next bid into account.
+	 * Update this with a new action that was done by the opponent that this
+	 * model is modeling. {@link #with(Domain)} must be called before calling
+	 * this.
+	 * 
+	 * @param action   the new incoming action.
+	 * @param progress the current progress of the negotiation. Calls to this
+	 *                 must be done with increasing progress.
+	 * @return the updated {@link OpponentModel}
 	 */
-	OpponentModel update(Bid bid);
+	OpponentModel with(Action action, Progress progress);
 
 }
Index: opponentmodel/src/test/java/geniusweb/profile/opponentmodel/FrequencyOppModelTest.java
===================================================================
--- opponentmodel/src/test/java/geniusweb/profile/opponentmodel/FrequencyOppModelTest.java	(revision 14)
+++ opponentmodel/src/test/java/geniusweb/profile/opponentmodel/FrequencyOppModelTest.java	(revision 18)
@@ -3,4 +3,5 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 
 import java.math.BigDecimal;
@@ -14,4 +15,6 @@
 import org.junit.Test;
 
+import geniusweb.actions.Offer;
+import geniusweb.actions.PartyId;
 import geniusweb.issuevalue.Bid;
 import geniusweb.issuevalue.DiscreteValue;
@@ -23,4 +26,5 @@
 import geniusweb.issuevalue.ValueSet;
 import geniusweb.opponentmodel.FrequencyOpponentModel;
+import geniusweb.progress.Progress;
 import tudelft.utilities.junit.GeneralTests;
 
@@ -32,4 +36,6 @@
 	private static final DiscreteValue I1V2 = new DiscreteValue("i1v2");
 	private static final DiscreteValue I1V2b = new DiscreteValue("i1v2b");
+	private static final Progress progress = mock(Progress.class);
+	private static final PartyId other = new PartyId("other");
 
 	private static Domain domain, domain2, domain3;
@@ -85,5 +91,5 @@
 		oppModel2 = new FrequencyOpponentModel(domain2);
 		oppModel3 = new FrequencyOpponentModel(domain3);
-		oppModel4 = (FrequencyOpponentModel) oppModel3.update(bid1);
+		oppModel4 = oppModel3.with(new Offer(other, bid1), progress);
 
 	}
@@ -106,5 +112,5 @@
 
 	@Test(expected = NullPointerException.class)
-	public void smokeNullTest() {
+	public void smokeTestNull() {
 		new FrequencyOpponentModel(null);
 	}
@@ -124,5 +130,6 @@
 	@Test
 	public void testUpdate() {
-		FrequencyOpponentModel oppModel = oppModel1.update(bid1);
+		FrequencyOpponentModel oppModel = oppModel1.with(new Offer(other, bid1),
+				progress);
 		assertTrue(BigDecimal.ONE.compareTo(oppModel.getUtility(bid1)) == 0);
 		assertTrue(BigDecimal.ZERO.compareTo(oppModel.getUtility(bid3)) == 0);
@@ -135,5 +142,7 @@
 		// bid1 and bid2 both want I1V1. They differ on the number value.
 		// bid3 wants I1V2 but does have the number value from bid2
-		FrequencyOpponentModel oppModel = oppModel1.update(bid1).update(bid2);
+		FrequencyOpponentModel oppModel = oppModel1
+				.with(new Offer(other, bid1), progress)
+				.with(new Offer(other, bid2), progress);
 		assertTrue(new BigDecimal("0.75")
 				.compareTo(oppModel.getUtility(bid1)) == 0);
