Ah, sorry - had the wrong end of the stick slightly
In the model I'd prefer the AI wouldn't be aware, since it would be output-only (i.e. - it would result in a sequence of game-state changes the UI needs to display, but which the UI cannot influence). This is important (and also applies to other players, which should be indistinguishable from AIs) because they may be (often will be in the player case) running remotely, with significant round-trip communications latencies. As such you really have to follow the queuing model, though you have the option of syncing it with local UI actions for the local player (only) to give them a lower-latency visual feedback path for non-committed actions (e.g. - display of possible paths before the actual choice is made and issued as a game-state changing command)
Depends where you place your order queue. If you maintain a local display-state cache, that caches the states of entities only in so far as the properties needed to render them are concerned (position and type essentially), and have both the render AND UI threads operate against this state, but the state-cache update fed asynchronously by a queue from a state update pipeline sourced from the game engine, then you achieve both goals:
1) Synchronicity of state between UI and render thread for the local player (only)
2) Asynchronous coupling to the actual game state, and therefore any AIs/other players
Now, in the absence of simultaneous turns, the only thing that can update the game state is a user action (during the player's turn) or a game-engine-sourced change (during other players' turns). This means that (absent simultaneous turns) the cached state will only ever change due to EITHER a game-engine-sourced change (via the async queue) OR a local player action (via the UI), so if you force flush the queue at the start of the player turn (i.e. - make them wait for any remaining queued updates to finish playing animations etc.) then there can never be a clash between the changes the UI thread seeks to make to the cached state, and changes that are asynchronously occurring in the game engine.
Once we introduce simultaneous turns things get more complex and the UI must be capable of coping with issued user commands failing to commit, but we can leave that for another day and just implement sequential turns first (note - that 'sequential' at this level doesn't preclude all-AIs simultaneously, it just precludes human actions overlapping AI or other human actions)
Ok. Naming conventions are really starting to confuse now.
Before trying to talk about anything again, lets establish a some keywords based on the structure of the engine.
I extended your diagram of the data model to reflect the different components of the UI:
A few notes on the diagram. The Networking layer mimics the same API as the game engine, hence is invisible for the UI, and forwards calls from and to remote UI's making it look like those UI's are on the same machine from the perspective of the game engine. Leaving the networking layer out of the picture results in a still working game!
Note that it is vital for the connection layer to receive notification when certain changes are made to the game state, so it can start animations on the graphics thread.
In simple words the diagram would read as follows, from top to bottom, skipping the internal working of the game engine:
The graphics engine exists of a GUI and a render engine. It can generate certain callbacks based on user input, but makes no (significant) state changes on itself. The connection layer is responsible for processing the callbacks of the graphics thread and is responsible for synchronizing the state of the graphics engine with that of the game engine. The networking layer is responsible for synchronizing game states between different computers and does so by intercepting all traffic between the UI's of this pc and the game engine running on this pc. The game engine on it's turn is responsible for keeping track of the game state and handling any queries on this game state.
Now. The problems I discussed are related to the little arrow between the connection layer (previously called UI) and the graphics engine.
As it turns out, the graphics engine will control user input, hence the connection layer must register listeners. (GUI demands this).
In my opinion, it is certain that the connection layer is responsible for processing GUI button presses. Example: User presses: increase research. The GUI library calls the callback of the graphics engine (same thread), which adds the event to the queu of "increase research" events to process for the connection layer. Once ready to process the event, the connection layer processes the event and makes a call to the game engine to change the research of the player. If the call returns succesfully, it means the state of the game has actually changed, hence this method may take a while if playing over the net. If the call was succesfull, the connection layer makes sure all values are also updated in the graphics engine. It could for example be that the connection layer has given a function pointer to the graphics engine and let the it poll the game engine directly, hence automatic updating of the values from the perspective of the connection layer.
Now come the two interesting questions.
First of all: does the connection layer knows about the time it takes to execute an animation, or does it also asume atomic behaviour when dealing with the graphics engine? (irrelevant for the AI) If so, the graphics engine will have to deal with orders that can stack up faster then it can display these events. Note that during the AI turn, the connection layer may receive dozens of state changes which result in animations.
Implementing it as atomic makes life easy at first, but makes other options, such as viewing enemy movement, harder to implement. Since enemy movement would be an atomic action in the eyes of the connection layer, dozens of enemy units may start moving in the same frame, hence you cannot follow all of them...
Secondly, even though it is clear the GUI callbacks are generated from within the graphics thread, this may not need to be the case for unit selection. We have a choice there: Either let the graphics engine make requests to the connection layer to select a unit or let it just forward any non GUI mouse clicks and let the connection layer figure out what to do. Basically: how much work related to unit (and city) control is done inside the graphics engine and what is done in the connection layer?
There is one thing we could do significantly different then described in the diagram I made if we dicide the connection layer asumes all interaction with the graphics engine is atomic: Instead of hosting a single foreground thread for the connection layer, we can use background threads that simulate all the behaviour of this thread. This is possible because all methods called from these threads to the game engine or graphics engine must be made thread safe anyway and there is no direct need for state information. Although possible, it may be preferable to lift some (or as mush as possible) responsibiliy regarding state information from the graphics engine to the connection layer, hence it I believe it is easier to create a single thread with a loop. That keeps track of the currently selected unit, whether you are zoomed into a city, etc.