Class Client
- All Implemented Interfaces:
AutoCloseable, Callable<String>
- Direct Known Subclasses:
Test.RandomClient
server to find a partner and play a
role in a storytelling session.
This abstract class implements the necessary communication protocol to
connect to the server, find a partner, and start a session. Each time a
status update arrives from the server that requires this
client to make a choice, the onChoice(Status) method is called to
determine what choice the agent wants to make.
This class provides several other methods that are all called from the same
thread at important moments in the client's lifecycle. These methods can be
overridden to, for example, log important information or update the client's
world model. See the call() method for a full description of these
methods and when they are called.
If the session begins and ends normally the client's call() method
returns the session ID of the completed session. If this client disconnects
early, or if a problem occurs that does not cause an uncaught exception, that
method will return null.
- Author:
- Stephen G. Ware
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intThe default network port the client will attempt to connect to if one is not explicitly provided in the constructorstatic final StringThe default URL the client will attempt to connect to if one is not explicitly provided in the constructorstatic final StringThe name of the environment variable where the client expects to find the API key used to authenticate with the service that provides functions which require special external resources or computation.static final StringThe name of the environment variable where the client expects to find the password this agent will use, unless the password is explicitly set by the agent's constructor. -
Constructor Summary
ConstructorsConstructorDescriptionConstructs a client with a given name, which has no preference for its role, world, or partner, reading the password and API key from the environment, and using the default network settings.Constructs a client with a name, role, and world name, which has no preference for a partner, reading the password and API key from the environment, and using the default network settings.Constructs a client with the given session preferences, reading the password and API key from the environment, and using the default network settings.Constructs a client with the given session preferences and network details, reading the password and API key from the environment.Client(String name, String password, String world, Role role, String partner, String key, String url, int port) Constructs a client with the given session preferences, password, API key, and network details. -
Method Summary
Modifier and TypeMethodDescriptionfinal Stringcall()voidclose()protected StringMakes an external call to a large language model API to complete a text prompt.protected SSLSocketEstablishes a secure socket to the server based on this client's network configuration.protected float[]Makes an external call to a large language model API to embed a text string in the model's latent space.If it is currently this client's turn to act, this method returns the list ofturnsthey can take next.Returns the list of allturnsthat have been taken so far in this client's session that this client has observed.getName()Returns the client's name.Returns the name of the partner this client wants to play with.getRole()Returns the role this client wants to play or is currently playing in its session.Returns the ID of this client's session.getState()Returns the currentstateof the story world.getWorld()Returns thestory worldin which this client's session is taking place.Returns the name of the story world this client will play in or is currently playing in.protected abstract intThis method is called each time it is this client's turn to make a choice in the story.protected voidonClose()This method is called once if the client wasclosed, if it was interrupted, or if the socket was disconnected.protected voidThis method is called after the client connects to the server and the server sends the list of available worlds and agents.protected voidIf the client ever established its connection to the server, this method is called once right before thecall()method returns or throws an exception.protected voidThis method is called once if the story reaches one of itspre-defined endings.protected voidThis method is called if the server reports anerrorto this client.protected voidThis method is called once when the client's session starts.protected voidThis method is called once when the client's session ends.protected voidThis method is called each time the story world changes as a result of a turn the client observes.protected voidThis method is called if this client encounters a problem which does not immediately require it to close but which may cause problems.protected Messagereceive()This method blocks until the client receives a message from the server and then returns that message.protected <M extends Message>
MThis method blocks until the client receives a message of a given type from the server.protected voidThis method sends a message to the server.protected voidSets the name this client will use.protected voidsetPartner(String partner) Sets the name of the partner this client wants to play in its session.protected voidsetPassword(String password) Sets the password this client will use.protected voidSets the role this client wants to play in its session.protected voidsetWorldName(String world) Sets the name of the story world this client wants to play in.toString()
-
Field Details
-
ENVIRONMENT_VARIABLE_PASSWORD
The name of the environment variable where the client expects to find the password this agent will use, unless the password is explicitly set by the agent's constructor. If this environment variable is not set and no password is provided in the constructor, this agent will not use a password.- See Also:
-
ENVIRONMENT_VARIABLE_API_KEY
The name of the environment variable where the client expects to find the API key used to authenticate with the service that provides functions which require special external resources or computation. If this environment variable is not set and no API key is provided in the constructor, this agent will not be able to use the external API.- See Also:
-
DEFAULT_URL
The default URL the client will attempt to connect to if one is not explicitly provided in the constructor- See Also:
-
DEFAULT_PORT
public static final int DEFAULT_PORTThe default network port the client will attempt to connect to if one is not explicitly provided in the constructor- See Also:
-
-
Constructor Details
-
Client
public Client(String name, String password, String world, Role role, String partner, String key, String url, int port) Constructs a client with the given session preferences, password, API key, and network details.- Parameters:
name- the name the client will usepassword- the password the client will provide to the server, or null if the client will not use a passwordworld- the name of the world the client wants their session to take place in, or null if the client has no preference for a story worldrole- the role the client wants to play in the session, or null if the client is willing to play either rolepartner- the name of the client's desired partner, or null if the client is willing to play with any partnerkey- the API key the client will use to access external resources and computation, or null if the client will not use the external APIurl- the URL of the server to which this client will connectport- the network port on which this client will connect
-
Client
Constructs a client with the given session preferences and network details, reading the password and API key from the environment. The client's password will be read fromENVIRONMENT_VARIABLE_PASSWORD. The client's API key will be read fromENVIRONMENT_VARIABLE_API_KEY.- Parameters:
name- the name the client will useworld- the name of the world the client wants their session to take place in, or null if the client has no preference for a story worldrole- the role the client wants to play in the session, or null if the client is willing to play either rolepartner- the name of the client's desired partner, or null if the client is willing to play with any partnerurl- the URL of the server to which this client will connectport- the network port on which this client will connect
-
Client
Constructs a client with the given session preferences, reading the password and API key from the environment, and using the default network settings.- Parameters:
name- the name the client will useworld- the name of the world the client wants their session to take place in, or null if the client has no preference for a story worldrole- the role the client wants to play in the session, or null if the client is willing to play either rolepartner- the name of the client's desired partner, or null if the client is willing to play with any partner
-
Client
Constructs a client with a name, role, and world name, which has no preference for a partner, reading the password and API key from the environment, and using the default network settings.- Parameters:
name- the name the client will useworld- the name of the world the client wants their session to take place in, or null if the client has no preference for a story worldrole- the role the client wants to play in the session, or null if the client is willing to play either role
-
Client
Constructs a client with a given name, which has no preference for its role, world, or partner, reading the password and API key from the environment, and using the default network settings.- Parameters:
name- the name the client will use
-
-
Method Details
-
toString
-
getName
-
setName
Sets the name this client will use.- Parameters:
name- the new name this client will use- Throws:
IllegalStateException- if the client has already joined the server
-
setPassword
Sets the password this client will use.- Parameters:
password- the new password this client will use- Throws:
IllegalStateException- if the client has already joined the server
-
getWorldName
Returns the name of the story world this client will play in or is currently playing in. A null value means this client's session has not yet started this client is willing to play in any world. Once the session starts, this method will return the name of the world the client is playing in.- Returns:
- the name of the client's story world
-
setWorldName
Sets the name of the story world this client wants to play in.- Parameters:
world- the name of the world this client wants to play in- Throws:
IllegalStateException- if the client has already joined the server
-
getRole
Returns the role this client wants to play or is currently playing in its session. A null value means this client's session has not yet started and this client is willing to play either role. Once the session starts, this method will return the role assigned to the client.- Returns:
- the client's role
-
setRole
Sets the role this client wants to play in its session.- Parameters:
role- the role this client wants to play in its session- Throws:
IllegalStateException- if the client has already joined the server
-
getPartner
Returns the name of the partner this client wants to play with. A null value means this client is willing to play with any partner. This value does not change when the session starts. In other words, if the client did not request a specific partner, they client has no way to know the name of the partner they were assigned.- Returns:
- the name of the partner this client wants to play with
-
setPartner
Sets the name of the partner this client wants to play in its session.- Parameters:
partner- the name of the partner this client wants to play with- Throws:
IllegalStateException- if the client has already joined the server
-
getWorld
Returns thestory worldin which this client's session is taking place.- Returns:
- the story world for this client's session
- Throws:
IllegalStateException- if the client's session has not yet started
-
getHistory
Returns the list of allturnsthat have been taken so far in this client's session that this client has observed. If the client is thegame master, they always observe all turns. If this client is theplayer, they may not observe all turns.- Returns:
- the list of all turns that have been taken so far in the session
- Throws:
IllegalStateException- if the client's session has not yet started
-
getState
Returns the currentstateof the story world.- Returns:
- the current state of the story world
- Throws:
IllegalStateException- if the client's session has not yet started
-
getChoices
If it is currently this client's turn to act, this method returns the list ofturnsthey can take next. If it is not thie client's turn, the list will be empty.- Returns:
- the list of turns the client can take next
- Throws:
IllegalStateException- if the client's session has not yet started
-
getSession
Returns the ID of this client's session. A session is only assigned after the session has ended, so the value returned by this method will always be null until the very end of this client's lifecycle.- Returns:
- the session ID of this client's session
-
call
This method connects to the server, joins, waits for a session to start, sends the choices made by this client, and eventually returns the session ID of the completed session.
As this method runs, it calls other methods to notify the client of important events. Some of these methods are guaranteed to be called even if an exception is thrown. The list of those methods and when they happen is as follows:
- The
connect(String, int)method is called to establish a secure socket to the server. If an exception is thrown by this method, it will be thrown immediately, and the rest of the methods below will not be called. - After the client receives the
connectmessage from the server,onConnect(Connect)is called. This is the client's last chance to make changes to its identity or session details. - After the client receives the
startmessage and the firstupdatemessage, the session begins and theonStart(World, Role, State)method is called. Immediately before that method is called, method likegetWorld()will be able to return their values. - Each time the client receives an
updatemessage, theonUpdate(Status)method is called to notify the client about changes to the session history and world state. This method is called whether or not the client need to make a choice. - Each time the client receives an
updatemessage and it is the client's turn to act, after callingonUpdate(Status)theonChoice(Status)method will be called to solicit which turn the client wants to take. After calling that method, thegetChoices()method will return an empty list. - If the session's story reaches one of its pre-defined endings, the
onEnd(Ending)method will be called. - If the session ended because this client was
closed, because the client thread was interrupted, or because the socket was disconnected, theonClose()method will be called. If an exception was thrown earlier in this method,onClose()will not be called. - If the session started, the
onStop(String)method will always be called before this method returns or throw an exception. - If the client successfully connected to the server, the
onDisconnect()method will always be called before this method returns or throws an exception.
- The
-
close
public void close()Disconnects this client from the server, causing it to stop. This method can be called safely from any thread. If this method is called before the client connects (e.g. before
call()), it does nothing.- Specified by:
closein interfaceAutoCloseable
-
connect
Establishes a secure socket to the server based on this client's network configuration.By default, this method uses Java's
Secure Socket Layerto create and return a new socket.- Parameters:
url- the URL of the serverport- the network port on which to open the socket- Returns:
- a secure socket connection to the server
- Throws:
IOException- if a problem occurred establishing the socketSecurityException- if a security manager exists and it does not allow the socket to be establishedUnknownHostException- if the URL of server is not knownIllegalArgumentException- if the network port is outside the specified range of valid port valuesException
-
receive
This method blocks until the client receives a message of a given type from the server. If the next message received is not of the correct type, this method throws an exception. If the client's connection to the server is closed before it receives a message, this method returns null.It is usually unsafe for implementations of this abstract class to call this method. The
call()method has specific expectations about when and what type of messages will be received. Calling this method at an unexpected time is likely to cause this client to get out of sync with the server.- Type Parameters:
M- the type of message the client expects- Parameters:
type- the message class this client expects to receive- Returns:
- the message received from the server, or null if the connection was closed
- Throws:
IllegalStateException- if the client has not yet connected to the server
-
receive
This method blocks until the client receives a message from the server and then returns that message. If the client's connection to the server is closed before it receives a message, this method returns null.- Returns:
- the message received from the server, or null if the connection was closed
- Throws:
IllegalStateException- if the client has not yet connected to the server- See Also:
-
send
This method sends a message to the server.It is usually unsafe for implementations of this abstract class to call this method. The
call()method has specific expectations about when and what type of messages should be sent. Calling this method at an unexpected time is likely to cause this client to get out of sync with the server.- Parameters:
message- the message to send to the server- Throws:
IllegalStateException- if the client has not yet connected to the server
-
onConnect
This method is called after the client connects to the server and the server sends the list of available worlds and agents. This method is typically the last chance the client has to change its identity, such as itsnameorrequested role, before the client's join request is sent.By default, this method does nothing. It can be overridden if the client wants to react to connecting to the server.
- Parameters:
connect- the connect message sent from the server- Throws:
Exception- if a problem occurs during this method
-
onStart
This method is called once when the client's session starts.By default, this method does nothing. It can be overridden if the client wants to react to its session starting.
- Parameters:
world- the story world in which the session will take placerole- the role this client will play in the storyinitial- the initial state of the story world before the story begins- Throws:
Exception- if a problem occurs during this method
-
onUpdate
This method is called each time the story world changes as a result of a turn the client observes. If this client is thegame master, it will observe all turns. If this client is theplayer, it may not observe all turns.By default, this method does nothing. It can be overridden if the client wants to react to a change in the world state.
- Parameters:
status- the current status of the story world, including the history of all turns and the current world state- Throws:
Exception- if a problem occurs during this method
-
onChoice
This method is called each time it is this client's turn to make a choice in the story. Calls to this method will always be preceded by a call toonStart(World, Role, State)if this is the start of the session oronUpdate(Status)if this is not the start of the session.- Parameters:
status- the current status of the story world, including thehistory of all turns so far, thecurrent stateof the world, and thelist of choicesavailable for the client to choose from- Returns:
- the index (starting at 0) of the turn this client wants to take
from the
list of choicesgiven - Throws:
Exception- if a problem occurs during this method
-
onEnd
This method is called once if the story reaches one of itspre-defined endings. If the session never starts or of the story does not reach an ending, this method will not be called.By default, this method does nothing. It can be overridden if the client wants to react to the end of the story.
- Parameters:
ending- the ending of the story- Throws:
Exception- if a problem occurs during this method
-
onStop
This method is called once when the client's session ends. If the session started, this method will always be called, even if an uncaught exception was thrown at an earlier stage in the client's lifecycle.By default, this method does nothing. It can be overridden if the client wants to react to the end of the session.
- Parameters:
message- the message explaining why the session ended, or null if no explanation was received- Throws:
Exception- if a problem occurs during this method
-
onClose
This method is called once if the client wasclosed, if it was interrupted, or if the socket was disconnected. This method will not be called if the client is stopping because an uncaught exception was thrown at an earlier stage of the client's lifecycle. This method is always called from thecall()method, meaning it will always run on the thread which called that method, even if a different thread called theclose()method.By default, this method does nothing. It can be overridden if the client wants to react to be closed.
- Throws:
Exception- if a problem occurs during this method
-
onDisconnect
If the client ever established its connection to the server, this method is called once right before thecall()method returns or throws an exception.By default, this method does nothing. It can be overridden if the client wants to react to the end of its lifecycle. This is a good method to clean up resources.
- Throws:
Exception- if a problem occurs during this method
-
onWarning
This method is called if this client encounters a problem which does not immediately require it to close but which may cause problems.By default, this method prints the warning to
standard error.- Parameters:
message- a description of the problem- Throws:
Exception- if this method throws an exception
-
onError
This method is called if the server reports anerrorto this client.By default, if the session has not yet started, this method throws a
RuntimeExceptionwhose message is the message passed to this method. If the session has started, the error will be printed tostandard errorand no exception will be thrown.- Parameters:
message- an explanation of what caused the error- Throws:
Exception- if this method throws an exception
-
complete
Makes an external call to a large language model API to complete a text prompt.This method requires the agent to have an
API key; without one, this method will throw an exception.- Parameters:
system- the system prompt which instructs the language model how to respond to the promptprompt- the prompt which the large language model will respond totemperature- a parameter influencing the predictability of the language model's output, where 0 means completely predictable and higher values mean less predictable (more "creative") output- Returns:
- the response from the large language model to the prompt
- Throws:
IllegalStateException- if the client does not have an API key
-
embed
Makes an external call to a large language model API to embed a text string in the model's latent space.This method requires the agent to have an
API key; without one, this method will throw an exception.- Parameters:
string- the string to embed- Returns:
- a vector representing the string's embedding
- Throws:
IllegalStateException- if the client does not have an API key
-