Skip to content

Commit

Permalink
Decouple DME
Browse files Browse the repository at this point in the history
  • Loading branch information
vladmaraev committed Aug 20, 2024
1 parent 7b14053 commit 9c0fd8f
Show file tree
Hide file tree
Showing 6 changed files with 1,043 additions and 152 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
},
"devDependencies": {
"typescript": "^5.2.2",
"vite": "^5.2.0"
"vite": "^5.2.0",
"vitest": "^2.0.5"
},
"dependencies": {
"@statelyai/inspect": "^0.2.5",
Expand Down
127 changes: 127 additions & 0 deletions src/dme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { setup, assign, sendTo, AnyTransitionConfig } from "xstate";
import { rules } from "./rules";
import { SaysMoveEvent, DMEEvent, DMEContext } from "./types";

function isuTransition(
nextState: string,
ruleName: string,
nextMove: boolean,
): AnyTransitionConfig {
return {
target: nextState,
guard: { type: "isu", params: { name: ruleName } },
actions: nextMove
? [
{ type: "isu", params: { name: ruleName } },
{ type: "sendBackNextMove" },
]
: [{ type: "isu", params: { name: ruleName } }],
};
}

export const dme = setup({
types: {} as {
input: DMEContext;
context: DMEContext;
events: DMEEvent;
},
guards: {
isu: ({ context }, params: { name: string }) =>
rules[params.name](context).preconditions,
},
actions: {
sendBackNextMove: sendTo(
({ context }) => context.parentRef,
({ context }) => {
return {
type: "NEXT_MOVE",
value: context.is.next_move,
};
},
),
isu: assign(({ context }, params: { name: string }) => {
return { is: rules[params.name](context).effects };
}),
updateLatestMove: assign(({ event }) => {
console.debug("[DM updateLatestMove]", event);
return {
latest_move: (event as SaysMoveEvent).value.move,
latest_speaker: (event as SaysMoveEvent).value.speaker,
};
}),
},
}).createMachine({
context: ({ input }) => {
return input;
},
initial: "Select",
states: {
Select: {
initial: "SelectAction",
states: {
SelectAction: {
always: [
isuTransition("SelectMove", "select_respond", false),
isuTransition("SelectMove", "select_from_plan", false),
{ target: "SelectMove" }, // TODO check it -- needed for greeting
],
},
SelectMove: {
always: [
isuTransition("SelectionDone", "select_ask", true),
isuTransition("SelectionDone", "select_answer", true),
isuTransition("SelectionDone", "select_other", true),
{ target: "SelectionDone" },
],
},
SelectionDone: { type: "final" },
},
onDone: "Update",
},
Update: {
initial: "Init",
states: {
Init: {
always: isuTransition("Grounding", "clear_agenda", false),
},
Grounding: {
// TODO: rename to Perception?
on: {
SAYS: {
target: "Integrate",
actions: [
{
type: "updateLatestMove",
},
{ type: "isu", params: { name: "get_latest_move" } },
],
},
},
},
Integrate: {
always: [
isuTransition("DowndateQUD", "integrate_usr_request", false),
isuTransition("DowndateQUD", "integrate_sys_ask", false),
isuTransition("DowndateQUD", "integrate_usr_ask", false),
isuTransition("DowndateQUD", "integrate_greet", false),
],
},
DowndateQUD: {
always: [
isuTransition("LoadPlan", "downdate_qud", false),
{ target: "LoadPlan" },
],
},
LoadPlan: {
always: { target: "ExecPlan" },
},
ExecPlan: {
type: "final",
},
},
onDone: {
target: "Select",
},
},
},
});
172 changes: 41 additions & 131 deletions src/isu.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
import {
assign,
createActor,
setup,
AnyMachineSnapshot,
raise,
AnyTransitionConfig,
} from "xstate";
import { createActor, setup, AnyMachineSnapshot, sendTo } from "xstate";
import { speechstate } from "speechstate";
import { createBrowserInspector } from "@statelyai/inspect";
import { KEY } from "./azure";
import { DMContext, DMEvent } from "./types";
import { rules } from "./rules";
import { DMContext, DMEvent, NextMoveEvent } from "./types";
import { nlg, nlu } from "./nlug";
import { dme } from "./dme";

const inspector = createBrowserInspector();

function isuTransition(
nextState: string,
ruleName: string,
): AnyTransitionConfig {
return {
target: nextState,
guard: { type: "isu", params: { name: ruleName } },
actions: { type: "isu", params: { name: ruleName } },
};
}

const azureCredentials = {
endpoint:
"https://northeurope.api.cognitive.microsoft.com/sts/v1.0/issuetoken",
Expand All @@ -42,41 +24,25 @@ const settings = {
};

const dmMachine = setup({
guards: {
/** preconditions */
isu: ({ context }, params: { name: string }) =>
rules[params.name](context).preconditions,
actors: {
dme: dme,
},
actions: {
/** effects */
isu: assign(({ context }, params: { name: string }) => {
return { is: rules[params.name](context).effects };
}),
/** update latest_move (outside IS!) based on ASR/TTS (SAYS event) */
updateLatestMove: assign(({ event }) => {
console.debug("[DM updateLatestMove]", event);
return {
latest_move: event.value.move,
latest_speaker: event.value.speaker,
};
}),
/** TTS */
speak_next_move: ({ context }) =>
speak_next_move: ({ context, event }) =>
context.ssRef.send({
type: "SPEAK",
value: {
utterance: nlg(context.is.next_move),
utterance: nlg((event as NextMoveEvent).value),
},
}),
/** ASR */
listen: ({ context }) =>
context.ssRef.send({
type: "LISTEN",
}),
},
types: {} as {
context: DMContext;
event: DMEvent;
events: DMEvent;
},
}).createMachine({
context: ({ spawn }) => {
Expand Down Expand Up @@ -135,8 +101,9 @@ const dmMachine = setup({
on: {
RECOGNISED: {
target: "Idle",
actions: raise(({ event }) => ({
actions: sendTo("dmeID", ({ event, self }) => ({
type: "SAYS",
sender: self,
value: {
speaker: "usr",
move: nlu(event.value[0].utterance),
Expand All @@ -146,16 +113,17 @@ const dmMachine = setup({
ASR_NOINPUT: {
target: "Idle",
// FOR TESTING
actions: raise({
actions: sendTo("dmeID", ({ self }) => ({
type: "SAYS",
sender: self,
value: {
speaker: "usr",
move: {
type: "ask",
content: (x: string) => `favorite_food ${x}`,
},
},
}),
})),
},
},
},
Expand All @@ -165,104 +133,41 @@ const dmMachine = setup({
initial: "Idle",
states: {
Idle: {
always: {
target: "Speaking",
guard: ({ context }) => !!context.is.next_move,
on: {
NEXT_MOVE: {
target: "Speaking",
actions: sendTo("dmeID", ({ event, self }) => ({
type: "SAYS",
sender: self,
value: {
speaker: "sys",
move: event.value,
},
})),
},
},
},
Speaking: {
entry: "speak_next_move",
on: {
SPEAK_COMPLETE: {
target: "Idle",
actions: [
raise(({ context }) => ({
type: "SAYS",
value: {
speaker: "sys",
move: context.is.next_move,
},
})),
assign(({ context }) => {
return { is: { ...context.is, next_move: null } };
}),
],
},
},
},
},
},
DME: {
initial: "Select",
states: {
Select: {
entry: ({ context }) =>
console.debug("[DM] ENTERING SELECT", context.is),
initial: "SelectAction",
states: {
SelectAction: {
always: [
isuTransition("SelectMove", "select_respond"),
isuTransition("SelectMove", "select_from_plan"),
{ target: "SelectMove" }, // TODO check it -- needed for greeting
],
},
SelectMove: {
always: [
isuTransition("SelectionDone", "select_ask"),
isuTransition("SelectionDone", "select_answer"),
isuTransition("SelectionDone", "select_other"),
{ target: "SelectionDone" },
],
},
SelectionDone: { type: "final" },
},
onDone: "Update",
},
Update: {
initial: "Init",
states: {
Init: {
always: isuTransition("Grounding", "clear_agenda"),
},
Grounding: {
// TODO: rename to Perception?
on: {
SAYS: {
target: "Integrate",
actions: [
{
type: "updateLatestMove",
},
{ type: "isu", params: { name: "get_latest_move" } },
],
},
},
},
Integrate: {
always: [
isuTransition("DowndateQUD", "integrate_usr_request"),
isuTransition("DowndateQUD", "integrate_sys_ask"),
isuTransition("DowndateQUD", "integrate_usr_ask"),
isuTransition("DowndateQUD", "integrate_greet"),
],
},
DowndateQUD: {
always: [
isuTransition("LoadPlan", "downdate_qud"),
{ target: "LoadPlan" },
],
},
LoadPlan: {
always: { target: "ExecPlan" },
},
ExecPlan: {
type: "final",
},
},
onDone: {
target: "Select",
},
invoke: {
src: "dme",
id: "dmeID",
input: ({ context, self }) => {
return {
parentRef: self,
latest_move: context.latest_move,
latest_speaker: context.latest_speaker,
is: context.is,
};
},
},
},
Expand All @@ -282,7 +187,12 @@ dmActor.subscribe((snapshot: AnyMachineSnapshot) => {
// is !== snapshot.context.is && console.log("[IS]", snapshot.context.is);
is = snapshot.context.is;
// console.log("IS", is);
console.log("%cState value:", "background-color: #056dff", snapshot.value);
console.log(
"%cState value:",
"background-color: #056dff",
snapshot.value,
snapshot.context.is,
);
});

export function setupButton(element: HTMLElement) {
Expand Down
Loading

0 comments on commit 9c0fd8f

Please sign in to comment.