simi
simi (Simulation Interface) runs declarative test workflows inside the
app. A workflow is a plain object with a list of steps: dispatch a store
action, assert on state, wait for a condition or capture a value. The runner
executes the steps in order and emits insights events as it goes.
Each run tags its session with simi, the app name, the workflow id and the
workflow’s own tags, so test sessions go through the same telemetry and
triage tools as real ones.
Exports
| Export | What it is |
|---|---|
defineWorkflow(workflow) | Identity helper that type-checks a SimiWorkflow |
executeWorkflow(workflow, dispatch, getState, getClient, opts?) | The runner. Resolves with a RunResult |
KEEP_MODEL_TAG | 'keep-model'. Workflows with this tag ignore modelOverride |
| Types | SimiWorkflow, WorkflowStep, ActionStep, AssertStep, WaitForStep, CaptureStep, Resolver, StateResolver, FindResolver, EvalResolver, ResultResolver, RunOpts, RunResult, StepResult |
A workflow
import { defineWorkflow } from 'simi';
export const basicChatFlow = defineWorkflow({
id: 'basic_chat_flow',
app: 'smartchats',
tags: ['smoke', 'chat'],
setupWorkflows: ['complete_onboarding'],
steps: [
{ waitFor: 'state.aiModel !== "" && state.agent !== null', timeout: 10000 },
{ action: 'sendMessageAsync', args: ['What is 2 + 2?'], timeout: 30000, wait: 500 },
{ assert: 'state.chatHistory.length >= 2', message: 'Chat should have user + assistant messages' },
],
});SimiWorkflow fields: id, app, tags?, setupWorkflows? and steps.
Steps
| Step | Fields | Does |
|---|---|---|
ActionStep | action, args?, id?, wait?, timeout? | Dispatches a store action. wait sleeps afterwards (divided by RunOpts.speed). The step fails if the action’s promise outlasts timeout |
AssertStep | assert, message? | Evaluates the expression. Falsy fails the workflow |
WaitForStep | waitFor, timeout? | Polls the expression until it is truthy or the timeout passes |
CaptureStep | capture, as? | Evaluates the expression and records the value in a simi_capture event |
Expressions are JavaScript strings evaluated with state (the store state)
and results (earlier action results by step label) in scope.
$resolve arguments
Action args can hold resolver objects that are filled in at step time:
{ action: 'editChatMessage', args: [
{ $resolve: 'state', path: 'chatHistory.0.id' },
'edited content',
] }
{ action: 'deleteSession', args: [
{ $resolve: 'find', path: 'sessions', match: { title: 'Untitled' } },
] }
{ action: 'apply', args: [
{ $resolve: 'result', step: 'compute_args', path: 'value' },
] }| Resolver | Fields | Reads |
|---|---|---|
state | path | A dotted path in the store state |
find | path, match?, index? | An item in the array at path |
result | step, path? | The return value of an earlier ActionStep with that id |
eval | fn(state, results?) | Whatever the function returns |
Setup workflows
setupWorkflows lists workflow ids that run before steps. They are looked
up in RunOpts.workflowRegistry. If one is missing or fails, the workflow
fails with that error. Setup workflows should be idempotent.
RunOpts
| Option | Notes |
|---|---|
speed | Divides every step wait. Default 1 |
modelOverride | Runs the workflow on this model: dispatches updateSettings({ aiModel }) first and replaces models pinned by updateSettings steps. Falls back to globalThis.__SMARTCHATS_E2E_MODEL__ |
workflowRegistry | Workflows by id, for setupWorkflows |
Running workflows in the app
createInsightStore in smartchats-common compiles each workflow passed in
its workflows config and mounts them on window.__<app>__.simi, keyed by
workflow id:
await window.__smartchats__.simi.workflows.basic_chat_flow();
window.__smartchats__.simi.list(); // every workflow idThe Playwright e2e specs in apps/smartchats/tests/e2e/ call workflows the
same way. The app’s workflows live in apps/smartchats/app/simi/workflows/
and are registered in apps/smartchats/app/simi/index.ts.
The runner emits simi_workflow_start, simi_step, simi_resolve,
simi_capture, simi_model_override and simi_workflow_complete. To pull
recent runs, use bin/save_session --app smartchats --tag simi.
See also
- smartchats-sessions for analyzing the sessions a run produces
- Source:
packages/simi/src/index.ts