My favorites | English | Sign in

Faster apps faster - GWT 2.0 with Speed Tracer New!

WaveProtocol.org

Learn about the Google Wave Federation Protocol and get involved

Google Wave Robots: Overview

Contents

  1. What Are Robots?
  2. Client Library Resources
  3. Robot Identity
  4. Robot Capabilities
  5. Robot Profiles
  6. Events
  7. Operations
  8. Annotations
  9. Versioning
  10. Troubleshooting

What Are Robots?

A robot is an automated participant on a wave. A robot can read the contents of a wave in which it participates, modify the wave's contents, add or remove participants, and create new blips and new waves. In short, a robot can perform many of the actions that any other participant can perform.

You can use a robot to perform actions such as the following:

  • modify information in a wave
  • interact with participants in a wave
  • communicate and synchronize information in a wave to the outside world or to other waves
  • access or modify state in a third-party (such as a database)

You can do many more things with robots than those listed here. Additionally, as we expand the capabilities of the API, robots will be able to take advantage of these new features.

Client Library Resources

Development of Google Wave robots requires an appropriate client library. We currently have client libraries for the Java™ and Python programming languages.

You can find out more information about the client libraries, file issues, and make feature requests on the Google Wave Resources home page on Google Project Hosting. This page also contains download links for the latest client libraries.

Robot Identity

A robot (as opposed to a gadget) actively participates in the wave through HTTP requests and responses using the Wave Robot protocol. You don't need to know the particulars of this protocol, however, as we provide both Java and Python client libraries which you can use to create and manage your robots. Documentation of the underlying Wave Robot HTTP protocol is forthcoming.

Currently, Wave supports robots built using Google App Engine, the scalable web application environment. AppEngine identifies web applications using an application.appspot.com web address. When you create robots using AppEngine, you also implicitly define an HTTP interface at the http://application.appspot.com URL. Wave will use this address when communicating with the robot (and this address implicitly defines a robot at this time).

The Java and Python client libraries allow you to design your robot without having to worry about handling and managing the individual HTTP requests. Because this is an early developer release, code may (and likely will) change in the future. However, the client libraries have been designed to be fairly stable. If you do wish to use the Wire Protocol directly, you are free to do so, but understand that this protocol may change in the future.

A user (or a UI extension) adds a robot to a wavelet like adding any other participant, using the robot's App Engine application ID followed by @appspot.com as its wave participant address. For instance, if the App Engine application ID for a robot is parrotybot, the wave participant address for the robot is parrotybot@appspot.com. Note that the robot is added by what appears to be an email address, though the Wave API will use an HTTP mechanism to contact the robot.

Note: For this developer preview release, all Wave robots must be implemented as Google App Engine applications. A future release will introduce the ability to host robots with any web host, at any web address.

Robot Capabilities

You define the behavior of your robot by defining the events which you wish your robot to be notified. Wave contacts the robot whenever one of these events occur, such as a change made to a wave in which the robot is a participant. The robot specifies which events it cares about in a capabilities.xml configuration file, which Wave retrieves from the robot the first time the robot is added to a wave.

A sample capabilities.xml file is shown below:

<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0"> 
<w:version>0.1</w:version> 
<w:capabilities> 
  <w:capability name="BLIP_SUBMITTED"/> 
  <w:capability name="DOCUMENT_CHANGED"/> 
</w:capabilities> 
</w:robot>

Note: this capabilities.xml file is auto-generated by the Python client library; users of the Java client library will need to create this file themselves.

Note that this file contains a single <capabilities> element consisting of one or more <capability> elements. Each capability consists of an event which the robot indicates to Wave its interest. When an event of that type occurs, the Wave will dispatch to the robot an HTTP request.

Every robot must serve its configuration file at the following URL path:

http://applicationURL/_wave/capabilities.xml

Robot Profiles

Robots may additionally provide meta-information (known as a profile), which identifies a robot to other users (and other robots). Information within this profile is shown within a profile card when you click on the robot's avatar:

A profile consists of the following information:

  • name specifies the human-readable name of the robot. This name will be displayed wherever you hover over the robot's avatar or display its profile card).
  • imageUrl specifies the URL to use for the robot's avatar image. For display within the profile card, dimensions of 100 x 100 pixels are recommended. (Larger images should be avoided as well.)
  • profileUrl specifies the URL where information about this profile is available. This URL can be any URL you wish and will be linked within the profile card.

A robot, by default, does not provide this profile information. For Java robots, you must add a Profile servlet to your application which responds with this data. In Python, you provide this information within the robot's constructor. Consult the client library documentation for more information.

If a profile is available for a robot, it will be accessible at the following address:

robotName.appspot.com/_wave/robot/profile

Sending an HTTP GET request to this address will return JSON containing the robot's profile properties:

{
  "profileUrl": "http://tricky-bot.appspot.com/",  
  "imageUrl": "http://tricky-bot.appspot.com/images/avatar.png",
  "name": "Tricky"
}

Robot Events

The following events which a robot may subscribe to are particularly important:

  • wavelet_blip_created fires when a new wave blip has been created.
  • wavelet_participants_changed fires whenever a participant (including another robot) is added or removed from the wave.
  • wavelet_title_changed fires whenever the wavelet title changes.
  • blip_contributors_changed fires whenever the editors of a blip change.
  • blip_deleted fires whenever a blip is deleted from the wavelet.
  • blip_submitted fires whenever a blip is submitted. Note that this event only fires once the user clicks Done or moves to another blip.
  • document_changed fires whenever content is added to a blip, at various intervals.

In addition to being event-driven, a robot can request that Wave contact it at regular intervals by specifying a schedule in the configuration file. These cron events allow the robot to perform actions that are not in direct response to changes to a wave, such as to update a wave with new information from an external system.

Note that a robot cannot contact Wave directly; it can only respond to wave-related events and cron events.

When an event occurs, Wave makes an HTTP request to the robot application using a HTTP POST, the same method used when someone submits a web form. All events regarding changes to wave data use the following URL path when contacting the robot:

http://applicationURL/_wave/robot/jsonrpc

Each request for this URL from Wave may encapsulate more than one event about a single wavelet. Recent events may be bundled together. Once the robot receives an event, it can decide if (and how) to respond by encapsulating a response in an operation.

Operations

A web request from Wave includes information about one or more events. The robot can respond with instructions to update any wave on which it is a participant, or to create new wavelets through operations in the wave event system.

A robot can perform operations on any wavelet in which it is a participant, and can also create new wavelets and waves. Operations performed by a robot are not reported back to the robot that did them, though they are reported to other participants in the affected wavelets, including other robots.

Operations are handled in the order they are received, and robots do not have any special privileges over other users. Robot operations are sent to the Wave and performed asynchronously; there is no guarantee that other participants may not perform their own operations in the intervening time. As a result, it is best to keep your operations as atomic as possible, and to understand that operations which you apply to the wave may not be applied immediately. A wave is a historical entity, and the content of a wave consists of its original content plus the cumulative operations that occur on that data.

The Java and Python application client libraries provide a complete interface for handling events and performing operations. For example, the Java event handler uses a web servlet to respond to Wave requests by parsing the event data into objects, then calling a method on the servlet for each event. The method generates operations by manipulating objects that represent the Wave data model. When the method returns, the servlet sends all of the operations back to Wave to be applied to the data.

Note: The format of the incoming event data and outgoing operations data are part of the Wave robot wire protocol. During this developer preview release, the details of the wire protocol may change. Once the protocol is stable, we will publish a specification describing the message formats. In the meantime, you can use the Java and Python client libraries to parse events and generate operations.

Annotations

The Google Wave document model supports tagging sections of text within a wavelet's Document elements via annotations. The Google Wave client uses some reserved annotations itself to denote textual styling issues, hyperlinks, and some metadata. You can also use your own annotations to tag certain strings of text for your own purposes. Many robots use annotations to perform operations on strings of text.

Note that these annotations, by themselves, are simply ways to mark selections of text. They may, or may not, have visible effects. How you use or process annotations is up to you. An annotation may simply contain meta-information about a text selection, or it may require additional processing by your robot to have some effect. (For an example of annotation processing, see Custom Annotations below.)

Wave Annotations

The Google Wave client uses annotations to style runs of text strings, defining each annotation with a start and end point (known as a range). For example, the following text string (as displayed to the user in the client) and its annotations are shown below:

The quick brown fox jumped over the lazy dog.

(4,19) : style/fontStyle=italic
(10,15) : style/color=rgb(150,75,0)
(36,40) : style/fontWeight=bold

The following table lists these reserved annotations:

Annotation Name namespace Usage
style/backgroundColor google Styling, Background (Highlight) color
style/color google Styling, Text color
style/fontFamily google Styling, Font Name
style/fontSize google Styling, Font Size (in Pts)
style/fontWeight google Styling, Font Weight (bold, italic)
style/textDecoration google Styling
style/verticalAlign google Styling, Vertical Alignment
link/manual google Hyperlink
lang google Language of the wrapped text
conv/title google Title of Wavelet (usually the first sentence unless set explicitly here)
conv/contentcreationtime google Styling

Note: These annotations are subject to change as we revise the Wave Federation data model.

You can view a Blip's annotations within Wave Sandbox by selecting Editor Debug from the right hand menu on a blip and then clicking on annotations in the Editor Debug dialog box.

Custom Annotations

You can also create your own annotations. Robots often use annotations to mark text and repurpose it for some other use. For example, a shopping robot might allow users to select items within a wavelet for a shopping list, extract those annotated items, and add them to a gadget.

Annotations should be tagged using unique identifiers. It's good practice to preface your annotations using a namespace, so that they don't collide with other annotations (or system annotations). Using the robot's robotname.appspot.com address as the annotation prefix neatly serves this purpose. (A typical annotation in such as case would be robotname.appspot.com/tagname.)

Annotations may additionally take on a value. In many cases, a value is not necessary; the annotation and its underlying text contains all information that is needed for designating the range of text. In other cases, an annotation requires a value. The system styling annotations take on values, for example, to denote font sizes, colors, families, and weights, for example.

Using annotations effectively within a robot generally requires one (or both) the following patterns (one active and one passive):

  • Actively scan the document for patterns, process the text, and add annotations. Some of our internal robots use this pattern to discover web links, for example.
  • Passively respond to <annotateSelection> actions within an extension installer, process the text, and remove the annotations. This pattern is described below.

Note that the first pattern is more computationally expensive.

Annotating Selections

If you wish to have a robot respond to new annotations, the following pattern is recommended:

  • Create some way to annotate the text initially. An extension installer that implements the <annotateSelection> action performs this task nicely.
  • Have the robot scan for document_changed events.
  • Within the robot's handler for the document_changed event, retrieve the annotations and store them in an array.
  • Process the annotations in whatever manner is appropriate.
  • Finally, delete the annotations when you're done, so that you don't "redo" any annotation logic. Alternatively, you could mark the annotations as processed in the annotation's value and check for that value next time.

The following extension installer annotates a selection as a "band name" using band-name.appspot.com/name as the annotation's key:

<extension 
    name="Band Name Tagger"
    description="Tags selected text as a band name and adds it to a blip"
    thumbnailUrl="http://band-name.appspot.com/preview.png">
  <author name="Tom Manshreck"/>
  <menuHook location="TOOLBAR" text="Tag Bandname"
      iconUrl="http://band-name.appspot.com/toolbaricon.png">
    <annotateSelection key="band-name.appspot.com/name" />
    <addParticipants>
      <participant id="band-name@appspot.com"/>
    </addParticipants>
  </menuHook> 
</extension> 

The following code will then monitor document_changed events and process any annotations denoted with the band-name.appspot.com/name key. Note that we delete the annotation and then process it by passing it to an addBandName() method.

def onDocumentChanged(properties, context):
  # Get the text of the blip
  blipId = properties['blipId']
  blip = context.GetBlipById(blipId)
  doc = blip.GetDocument()
  text = doc.GetText()
  
  # Set up our array to hold the retrieved annotations
  bandnames = []

  # Get the annotation start and end points and add
  # them to the array
  for ann in blip.annotations:
    if ann.name == 'band-name.appspot.com/name':
      bandnames.append((ann.range.start, ann.range.end))

  # for each bandname, call addBandName to do any post processing
  # Also make sure to delete the existing annotation
  for start, end in bandnames:
    bandname = text[start:end]
    range = document.Range(start, end)
    doc.DeleteAnnotationsInRange(range, 'band-name.appspot.com/name')
    addBandName(context,bandname)

For more information about annotations, check out the Wave Linker Robot in the Wave Samples Gallery.

Robot Versioning

Robots within the Wave API are now versioned. This allows the Wave system to detect when robots have changed and/or their capabilities have been altered. If you modify a robot's capabilities (by adding or removing monitored events, for example), you should also change the version identifier of the Robot (which is currently just a text string).

Note that this version identifier is contained within the Robot's capabilities.xml file (for Java) or indicated in the Robot's constructor (for Python). This robot version identifier is not related to App Engine's versioning system. (App Engine versions allow you to deploy multiple versions of code to different clients.)

Robot Troubleshooting

The Robot architecture is new and full debugging tools are not yet available. However, if you have trouble during development of your robot, the following tests may be helpful:

  • Is your robot's capabilities.xml file live? You can test whether the file is properly deployed by accessing the robot at http://robotname.appspot.com/_wave/capabilities.xml. If you receive an XML response, you know your robot has been properly deployed to App Engine.
  • Is your robot properly versioned? If you've changed the capabilities of this robot, you will need to up the version number. (Note that this version number is not the App Engine version number but the version number of the robot contained within the capabilities.xml file.)
  • Are you monitoring the right events? Within the capabilities.xml, is your robot set up to receive the correct events?
  • Is App Engine serving the correct version? App Engine allows you to deploy multiple versions as well. Though you likely should not change this during development, you may wish to do so in production to avoid breaking existing waves and/or clients.
  • Is there an error in the App Engine Logs? Consult the App Engine logs at https://appengine.google.com for your robot deployment. If you receive an error, you likely have a coding error.

We welcome your feedback during this developer preview! Please post your comments and suggestions to the Google Wave API group.