A small helpdesk system: an office Pixel running a patched GrapheneOS Dialer answers technician calls, records both call legs as separate channels, and a Ruby backend transcribes them through Whisper and files an AI summary against the caller. Squashed to a single commit for sharing. No credentials are included; secrets live outside the repo in /etc/helpdesk/env on the server or a gitignored .claude/env.local locally. See .claude/env.local.example for the shape. Start at README.md, then docs/architecture.md.
72 lines
3.6 KiB
Java
72 lines
3.6 KiB
Java
package com.android.dialer.helpdesk.command;
|
|
|
|
import static com.android.dialer.helpdesk.command.CommandGate.CallPhase.ACTIVE;
|
|
import static com.android.dialer.helpdesk.command.CommandGate.CallPhase.ENDED;
|
|
import static com.android.dialer.helpdesk.command.CommandGate.CallPhase.RINGING;
|
|
import static com.android.dialer.helpdesk.command.CommandGate.Decision.APPLY;
|
|
import static com.android.dialer.helpdesk.command.CommandGate.Decision.DROP_BAD_ARG;
|
|
import static com.android.dialer.helpdesk.command.CommandGate.Decision.DROP_DUPLICATE;
|
|
import static com.android.dialer.helpdesk.command.CommandGate.Decision.DROP_STALE;
|
|
import static com.android.dialer.helpdesk.command.CommandGate.Decision.DROP_UNKNOWN_VERB;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.InputStreamReader;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Standalone off-device test for {@link CommandGate}. Modes:
|
|
* - default: decision assertions.
|
|
* - "verbs": print the sorted verb set (harness diffs vs Helpdesk::COMMAND_VERBS).
|
|
* - "dtmf": read args from stdin, print valid/invalid (harness diffs vs valid_dtmf?).
|
|
*/
|
|
public class CommandGateTest {
|
|
static int pass = 0, fail = 0;
|
|
static void eq(Object got, Object want, String d) {
|
|
if (got == null ? want == null : got.equals(want)) { pass++; System.out.println(" ok " + d); }
|
|
else { fail++; System.out.println(" FAIL " + d + " (got: " + got + ")"); }
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
if (args.length > 0 && args[0].equals("verbs")) {
|
|
List<String> v = new ArrayList<>(CommandGate.VERBS);
|
|
Collections.sort(v);
|
|
for (String s : v) System.out.println(s);
|
|
return;
|
|
}
|
|
if (args.length > 0 && args[0].equals("dtmf")) {
|
|
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
|
|
String line;
|
|
while ((line = r.readLine()) != null) {
|
|
System.out.println(CommandGate.isValidDtmf(line) ? "valid" : "invalid");
|
|
}
|
|
return;
|
|
}
|
|
CommandGate g = new CommandGate();
|
|
eq(g.decide("1", "answer", null, RINGING), APPLY, "answer on ringing applies");
|
|
eq(g.decide("1", "answer", null, RINGING), DROP_DUPLICATE, "same id dropped (idempotent)");
|
|
eq(g.decide("2", "answer", null, ENDED), DROP_STALE, "answer on ended dropped (monotonic)");
|
|
eq(g.decide("3", "explode", null, RINGING), DROP_UNKNOWN_VERB, "unknown verb dropped");
|
|
eq(g.decide("4", "dtmf", "5", ACTIVE), APPLY, "valid dtmf applies");
|
|
eq(g.decide("5", "dtmf", "X", ACTIVE), DROP_BAD_ARG, "bad dtmf arg dropped");
|
|
eq(g.decide("6", "dtmf", "#", ACTIVE), APPLY, "'#' is a valid dtmf");
|
|
eq(g.decide("7", "mute", null, ACTIVE), APPLY, "mute applies mid-call");
|
|
eq(g.decide("8", "hangup", null, ACTIVE), APPLY, "hangup applies mid-call");
|
|
eq(g.decide("9", "route", "bluetooth", ACTIVE), APPLY, "route applies");
|
|
// a bad command is never recorded as seen -> a corrected retry with the same id still evaluates
|
|
eq(g.decide("3", "answer", null, RINGING), APPLY, "id reused after prior unknown-verb still applies");
|
|
|
|
// bounded seen set (no unbounded growth over a long-running service) + per-call reset
|
|
CommandGate g2 = new CommandGate();
|
|
for (int i = 0; i < CommandGate.MAX_SEEN + 500; i++) {
|
|
g2.decide("id" + i, "mute", null, ACTIVE);
|
|
}
|
|
eq(g2.seenSize() <= CommandGate.MAX_SEEN, true, "seen set bounded at MAX_SEEN (no leak)");
|
|
g2.reset();
|
|
eq(g2.seenSize(), 0, "reset() clears dedup memory (per-call scope)");
|
|
eq(g2.decide("id0", "mute", null, ACTIVE), APPLY, "id re-applies after reset()");
|
|
System.out.println("\n" + pass + " passed, " + fail + " failed");
|
|
System.exit(fail == 0 ? 0 : 1);
|
|
}
|
|
}
|