Package edu.neu.ccs.task.agent

Source Code of edu.neu.ccs.task.agent.Agent

package edu.neu.ccs.task.agent;

import java.io.PrintWriter;
import java.util.List;
import java.util.Map;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import edu.neu.ccs.task.DecompositionPlan;
import edu.neu.ccs.task.Plan;
import edu.neu.ccs.task.Priority;
import edu.neu.ccs.task.Script;
import edu.neu.ccs.task.StepPlan;
import edu.neu.ccs.task.Task;
import edu.neu.ccs.task.TaskEngine;
import edu.neu.ccs.task.TaskModelSet;
import edu.neu.ccs.task.TaskPlan;
import edu.neu.ccs.task.dialogue.Display;
import edu.neu.ccs.task.dialogue.Output;
import edu.neu.ccs.task.dialogue.Turn;
import edu.neu.ccs.task.dialogue.WidgetUserAction;
import edu.neu.ccs.task.util.Bool;
import edu.neu.ccs.task.util.CollectingVisitor;
import edu.neu.ccs.task.util.Pair;
import edu.neu.ccs.task.util.Visitor;

/**
* A very simple dialogue agent designed for system-directed dialogue with
* multiple choice input.
* <p>
* The agent tracks its intentional state using a plan tree, and maintains
* dialogue state by keeping track of a <em>focus</em> within that tree.
* At each turn, it tries to find an elaboration that adds to the plan
* tree as near the focus as possible, and has a primitive task as a
* leaf.  It then adds this to the tree and executes the task (which
* becomes the new focus).
* <p>
* This class provides no UI; see {@link AgentConsole} and
* {@link AgentServer}, which both build (different) UIs on top of it.
*
* @author Dan Schulman
* @version $Id: Agent.java 1009 2011-01-21 21:02:36Z schulman $
*/
public class Agent {
  private final TaskEngine engine;
  private Plan focus;
  private Turn currentTurn;
  private Output currentOutput;
  private Output currentAltOutput;
  private List<Pair<String, Integer>> currentInputMenu;
  private String currentInputPrompt;
  private Pair<String, Map<String, String>> currentInputWidget;
 
  public static final String VERSION = "0.17 internal";
 
  public Agent() {
    this(null);
  }
 
  public Agent(TaskEngine engine) {
    this.engine = (engine!=null) ? engine :
      new TaskEngine(new TaskModelSet());
  }
 
  /**
   * @return the task engine we are using
   */
  public TaskEngine getEngine() {
    return engine;
  }
 
  public TaskModelSet getModelSet() {
    return engine.getModelSet();
  }
 
  /**
   * @return whether the agent is working on a live top-level goal.
   */
  public boolean isLive() {
    return (focus != null) && focus.getTop().isLive();
  }
 
  /**
   * @return the current focus (null if no top-level goal).
   */
  public Plan getFocus() {
    return focus;
  }
 
  /**
   * @return the current focus (null if no top-level goal).
   */
  public Task getFocusTask() {
    return (focus == null) ? null : focus.getThisTask();
  }
 
  /**
   * @return the current top-level plan (may be null)
   */
  public Plan getTop() {
    return (focus == null) ? null : focus.getTop();
  }
 
  /**
   * @param focus set the focus (null means no top-level plan)
   */
  public void setFocus(Plan focus) {
    this.focus = focus;
    focus.attach();
    setCurrentTurn(null);
  }
 
  private void setCurrentTurn(Turn turn) {
    currentTurn = turn;
    currentOutput = null;
    currentAltOutput = null;
    currentInputMenu = null;
    currentInputPrompt = null;
    currentInputWidget = null;
  }

  public boolean hasCurrentTurn() {
    return currentTurn != null;
  }
 
  public Display getCurrentDisplay() {
    if (currentTurn!=null && currentTurn.hasDisplay())
      return currentTurn.getDisplay();
    return null;
  }
 
  private Output getCurrentOutput() {
    if (currentOutput==null && currentTurn!=null && currentTurn.hasOutputText())
      currentOutput = currentTurn.getOutputText();
    return currentOutput;
  }
 
  public String getCurrentPlainOutput() {
    Output o = getCurrentOutput();
    return o==null ? null : o.getPlain(getFocusTask());
  }
 
  public String getCurrentAnnotatedOutput() {
    Output o = getCurrentOutput();
    return o==null ? null : o.getAnnotated(getFocusTask());
  }
 
  private Output getCurrentAltOutput() {
    if (currentAltOutput==null && currentTurn!=null && currentTurn.hasOutputText())
      currentAltOutput = currentTurn.getAltOutputText();
    return currentAltOutput;
  }
 
  public String getCurrentPlainAltOutput() {
    Output o = getCurrentAltOutput();
    return o==null ? null : o.getPlain(getFocusTask());
  }
 
  public String getCurrentAnnotatedAltOutput() {
    Output o = getCurrentAltOutput();
    return o==null ? null : o.getAnnotated(getFocusTask());
  }
 
  public List<Pair<String, Integer>> getCurrentInputs() {
    if (currentInputMenu==null && currentTurn!=null && currentTurn.hasUserMenu())
      currentInputMenu = currentTurn.getUserMenu().getInputs(
        getFocusTask(), 6, currentTurn.hasOutputText());
    return currentInputMenu;
  }
 
  public String getCurrentInputPrompt() {
    if (currentInputPrompt==null && currentTurn!=null && currentTurn.hasUserText())
      currentInputPrompt = currentTurn.getUserText().getPrompt(getFocusTask());
    return currentInputPrompt;
  }
 
  public Pair<String, Map<String, String>> getCurrentInputWidget() {
    if (currentInputWidget==null && currentTurn!=null && currentTurn.hasUserWidget()) {
      WidgetUserAction wua = currentTurn.getUserWidget();
      currentInputWidget = Pair.create(
          wua.getUrl(),
          wua.getParameters(getFocusTask()));
    }
    return currentInputWidget;
  }
 
  private boolean getElaboratedLive(final Visitor<Plan> v) {
    Plan plan = focus;
    while (!plan.isLive())
      plan = plan.getParent();
   
    return plan.getBottommostLive(new Visitor<Plan> () {
      public boolean visit(Plan p) {
        return getElaboratedLive(p, v);
      }
    });
  }
 
  private boolean getElaboratedLive(Plan p, final Visitor<Plan> v) {
    if ( ! p.isLive())
      return false;
   
    for (Plan child : p.getChildren())
      if (child.isLive())
        if (getElaboratedLive(child, v))
          return true;
   
    Visitor<Plan> v2 = new Visitor<Plan>() {
      public boolean visit(Plan p2) {
        return getElaboratedLive(p2, v);
      }
    };
    return p.elaborate(v2) || v.visit(p);
  }
 
  private boolean performPlan(Plan p) {
    return skipSufficientPostcondition(p) || performAtomic(p);
  }
 
  private boolean closePlan(List<Plan> agenda) {
    return closeWithSuccess(agenda) || closeAny(agenda);
  }
 
  private boolean skipSufficientPostcondition(Plan p) {
    if (p instanceof TaskPlan) {
      TaskPlan task = (TaskPlan) p;
      if (Bool.isTrue(task.getTask().isAchieved())) {
        setFocus(task);
        task.close();
        return true;
      }
    }
   
    return false;
  }
 
  private boolean performAtomic(Plan p) {
    if (p instanceof TaskPlan) {
      TaskPlan plan = (TaskPlan) p;
      Task task = plan.getTask();

      // First try to do it as a dialogue turn
      List<Turn> turns = getModelSet().getTurns(plan.getQName());
      for (Turn turn : Priority.copyShuffleSort(turns))
        if (Bool.maybeTrue(turn.isApplicable(task))) {
          setFocus(plan);
          setCurrentTurn(turn);
          return true;
        }

      // If not, try to execute a script
      List<Script> scripts = getModelSet().getScripts(plan.getQName());
      for (Script script : Priority.copyShuffleSort(scripts))
        if (Bool.maybeTrue(script.isApplicable(task))) {
          setFocus(plan);
          script.apply(task, true);
          performedFocus(null);
          return true;
        }
    }
   
    return false;
  }
 
  private boolean closeWithSuccess(List<Plan> agenda) {
    for (Plan p : agenda)
      if (p.computeSuccess()) {
        setFocus(p);
        p.close();
        return true;
      }
    return false;
  }
 
  private boolean closeAny(List<Plan> agenda) {
    if (! agenda.isEmpty()) {
      setFocus(agenda.get(0));
      focus.close();
      return true;
    }
    return false;
  }
 
  /**
   * Advance (by repeatedly generated elaborations for the plan
   * tree) until we have a primitive task to execute that is
   * realized by a dialogue turn.
   *
   * @return true if there is a next turn (false if done)
   */
  public boolean nextTurn() {
    if ((currentTurn == null) && isLive()) {
      CollectingVisitor<Plan> cv = new CollectingVisitor<Plan>() {
        public boolean visit(Plan p) {
          super.visit(p);
          return performPlan(p);
        }
      };
     
      if (getElaboratedLive(cv) || closePlan(cv.items()))
        engine.update();
      else
        throw new RuntimeException("no viable actions");
    }
    return currentTurn != null;
  }
 
  private void performedFocus(Boolean success) {
    Task task = getFocusTask();
    task.setWhen(System.currentTimeMillis());
    if (success != null)
      task.setSuccess(success);
    focus.close();
    setCurrentTurn(null);
    engine.update();
  }
 
  public void applyCurrentTurn() {
    currentTurn.apply(getFocusTask());
    performedFocus(true);
  }
 
  public void applyCurrentTurn(int choice) {
    currentTurn.applyChoice(getFocusTask(), choice);
    performedFocus(true);
  }
 
  public void applyCurrentTurn(String input) {
    currentTurn.applyInput(getFocusTask(), input);
    performedFocus(true);
  }
 
  public void failCurrentTurn() {
    if (currentTurn != null)
      performedFocus(false);
  }
 
  public boolean status(PrintWriter out, String type) throws XMLStreamException {
    if ("plan".equals(type)) {
      planTree(out);
      return true;
    } else
      return false;
  }
 
  private void planTree(PrintWriter out) throws XMLStreamException {
    XMLOutputFactory xof = XMLOutputFactory.newInstance();
    XMLStreamWriter xw = xof.createXMLStreamWriter(out);
    xw.writeStartDocument("UTF-8", "1.0");
   
    planTree(xw, getTop());
   
    xw.writeEndDocument();
    xw.flush();
  }
 
  private void planTree(XMLStreamWriter xw, Plan plan) throws XMLStreamException {
    if (plan instanceof TaskPlan) {
      TaskPlan tp = (TaskPlan) plan;
      xw.writeStartElement("TASK");
      xw.writeAttribute("ID", tp.getTask().toString());
    } else if (plan instanceof DecompositionPlan) {
      DecompositionPlan dp = (DecompositionPlan) plan;
      xw.writeStartElement("RECIPE");
      xw.writeAttribute("ID", dp.getType().toString());
    } else if (plan instanceof StepPlan) {
      StepPlan sp = (StepPlan) plan;
      xw.writeStartElement("STEP");
      xw.writeAttribute("NAME", sp.getName());
    } else
      return;
   
    if (plan == focus)
      xw.writeAttribute("STATUS", "FOCUS");
    else if (plan.isFailed())
      xw.writeAttribute("STATUS", "FAILED");
    else if (plan.isSuccessful())
      xw.writeAttribute("STATUS", "DONE");
    else if (plan.isLive())
      xw.writeAttribute("STATUS", "LIVE");
    else
      xw.writeAttribute("STATUS", "UNSTARTED"); // always correct??
     
    for (Plan child : plan.getChildren())
      planTree(xw, child);
   
    xw.writeEndElement();
  }
 
  public static void main(String[] args) throws Exception {
    AgentMain.main(args);
  }
}
TOP

Related Classes of edu.neu.ccs.task.agent.Agent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.