Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,44 @@ previous step's heading gone), not by sleeping.
5. The conversation gets its generated name, which is neither the question nor the answer, and the
sidebar shows it.

## The Bot's computer and approvals

The `computer-*` and `approvals-*` journeys:

| Journey | What a person does |
| --- | --- |
| `computer-browse` | Asks a Bot to read a page. The Computer opens on its live screen; the answer comes from the page; Activity lists the page with its time, and still does after a reload; the conversation folds the browsing into one line that opens to its steps. |
| `computer-take-control` | Opens the Bot's screen full size, takes control, goes somewhere from the address bar, back, forward, reload, opens a tab and closes it, is asked before clearing the browser, and hands it back. Stops and resets the Bot's browser in Settings → Computer. |
| `computer-terminal` | Asks a Bot to run a command: Activity shows it with what it printed. Takes control of the Terminal, types a command, hands it back. |
| `computer-form` | Asks a Bot to fill in and send a form from one message, its fields and checkbox in one step: every action runs, the form arrives filled in, and Activity lists each with its time. |
| `computer-sign-in` | A Bot reaches a password field and hands it over (no standing answer offered). The person takes control, types the password into the Bot's screen, hands back and answers "I did it myself"; the Bot carries on from the signed-in page. |
| `approvals-allow-once` | A Bot paying asks first. Allow once places that order and the reply arrives whole; the next order asks again, and waits on the Bots page under Needs you too; Deny there places nothing and the Bot says so. |
| `approvals-this-conversation` | Allow for this conversation: the next order there goes through with no card, the banner says what is allowed, Turn off makes the next order ask again. |
| `approvals-always` | Always allow here: the Bot pays without asking in its next conversation; the rule is on the Bot's Approvals page, where Remove takes it away. |
| `approvals-settings` | Settings → Approvals: Extra vigilant, Auto-review and commands on this computer, kept across a reload; a rule for every Bot added, changed, removed, and cancelled. |

Two things they do that other journeys may want to copy:

- **The run's own website.** The pages a Bot reads, the form it fills in and the checkout it pays at
are `e2e/site/site.ts`, served on `127.0.0.1:46600` while such a journey runs, never a third-party
site. The Bot's browser, in the computer's container, reaches it at
`http://host.docker.internal:46600` (Docker Desktop carries that to this machine's loopback). The
port is fixed whatever `E2E_PORT_OFFSET` says, because the address is in what the person types and
so in every fixture. The site counts the orders placed and the forms sent, so a journey checks what
the Bot did, not only what it said.
- **A Bot of its own for each journey** (`makeBot`, a fixture in `journeys/computer-steps.ts`), made
through the API as setup and deleted when the journey ends, pass or fail. A Bot's browser numbers
its page snapshots from its first, and a recorded click carries that number: on a Bot another
journey had browsed with, it would be out of date. A new Bot's browser starts from the beginning
whichever journeys ran first, an answer or a rule one journey gives stays with its Bot, and the
journeys after it see only the Bots they expect.

A reply is waited for by what it says (`replyAfter` in `journeys/computer-steps.ts`): a turn that
uses the computer is several runs, and between two of them the last one has finished with a sentence
like "I'm opening the page". It is then checked on screen word for word, once, as the Markdown renders.
Each conversation is also waited for until it has its name, so the naming call is made, and recorded,
inside the journey that caused it.

## What is and isn't under aimock

Every model call on this path goes to aimock: `OPENAI_BASE_URL` and `ANTHROPIC_BASE_URL` point at it
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"fixtures": [
{
"match": {
"userMessage": "You choose which capabilities to load for the message below. You are not answering it.\n\nCapabilities available:\n- research-public-web: Research the public web. Search current public sources and write a cited brief.\n- find-a-document: Find a document. Search the connected document sources for a file and read what it says.\n- find-a-notion-page: Find a Notion page. Search Notion for a page and read what it says.\n- skill-creator: Write a skill. Interview me about a skill I want, then write it and save it as a new skill.\n- bot-creator: Make a Bot. Work out what a new Bot should be, then put it in front of you to create.\n\nMessage:\nOpen http://host.docker.internal:46600/shop/tomato and place the order for the tomato seeds. Then tell me the order number in one short sentence.\n\nReply with only JSON: {\"skills\": [\"<slug>\", ...]}.\nChoose every capability that might be needed, including ones you are only somewhat sure about.\nChoosing one that turns out to be unnecessary costs almost nothing. Failing to choose one that\nwas needed means the work cannot be done at all, because its tools will not be loaded. When in\ndoubt, include it. Use an empty list only when the message plainly needs none of them.",
"model": "gpt-5.6-terra",
"turnIndex": 0,
"hasToolResult": false
},
"response": {
"content": "{\"skills\":[]}",
"usage": {
"prompt_tokens": 279,
"completion_tokens": 51,
"total_tokens": 330,
"prompt_tokens_details": {
"cached_tokens": 0,
"cache_write_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 35,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"fixtures": [
{
"match": {
"userMessage": "Open http://host.docker.internal:46600/shop/tomato and place the order for the tomato seeds. Then tell me the order number in one short sentence.",
"model": "gpt-5.6-terra",
"turnIndex": 0,
"hasToolResult": false
},
"response": {
"content": "I’m opening the Fernhill Garden Supply tomato page to order the tomato seeds.",
"toolCalls": [
{
"name": "computer_navigate",
"arguments": "{\"url\":\"http://host.docker.internal:46600/shop/tomato\"}",
"id": "call_J9oN5NgeOjL0RJqNNAplkAMt"
}
]
},
"recordedTimings": {
"ttftMs": 994,
"interChunkDelaysMs": [
28,
475,
227,
4,
4,
3,
4,
5,
3,
5,
9,
10,
3,
8,
0,
0,
11,
5,
5,
3,
0,
149,
5,
3,
2,
4,
2,
0,
0,
0,
8,
13,
7,
3,
2,
2,
0,
0,
12,
10,
7,
15,
179,
12,
547
],
"totalDurationMs": 2788
},
"metadata": {
"systemHash": "800ac84f",
"toolsHash": "6d7140c9"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"fixtures": [
{
"match": {
"userMessage": "Open http://host.docker.internal:46600/shop/tomato and place the order for the tomato seeds. Then tell me the order number in one short sentence.",
"model": "gpt-5.6-terra",
"turnIndex": 2,
"hasToolResult": true
},
"response": {
"toolCalls": [
{
"name": "computer_snapshot",
"arguments": "{}",
"id": "call_Hbh3csZHpnbxW3QFeLZhupBT"
}
]
},
"recordedTimings": {
"ttftMs": 877,
"interChunkDelaysMs": [
21,
360,
416,
5,
0,
160,
0,
175
],
"totalDurationMs": 2014
},
"metadata": {
"systemHash": "800ac84f",
"toolsHash": "6d7140c9"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"fixtures": [
{
"match": {
"userMessage": "Asked: Open http://host.docker.internal:46600/shop/tomato and place the order for the tomato seeds. Then tell me the order number in one short sentence.",
"model": "gpt-5.6-terra",
"turnIndex": 0,
"hasToolResult": false
},
"response": {
"content": "Tomato Seeds Order",
"usage": {
"prompt_tokens": 155,
"completion_tokens": 18,
"total_tokens": 173,
"prompt_tokens_details": {
"cached_tokens": 0,
"cache_write_tokens": 0,
"audio_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 5,
"audio_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
}
},
"metadata": {
"systemHash": "dedd9ec9"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"fixtures": [
{
"match": {
"userMessage": "Open http://host.docker.internal:46600/shop/tomato and place the order for the tomato seeds. Then tell me the order number in one short sentence.",
"model": "gpt-5.6-terra",
"turnIndex": 3,
"hasToolResult": true
},
"response": {
"toolCalls": [
{
"name": "computer_click",
"arguments": "{\"ref\":\"e13\",\"snapshotId\":2}",
"id": "call_cDQKqnn7ubgsG4kqN1d5dzGz"
}
]
},
"recordedTimings": {
"ttftMs": 817,
"interChunkDelaysMs": [
34,
577,
314,
3,
2,
3,
2,
129,
0,
0,
0,
0,
0,
0,
0,
14,
1,
175
],
"totalDurationMs": 2071
},
"metadata": {
"systemHash": "800ac84f",
"toolsHash": "6d7140c9"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"fixtures": [
{
"match": {
"userMessage": "Open http://host.docker.internal:46600/shop/tomato and place the order for the tomato seeds. Then tell me the order number in one short sentence.",
"model": "gpt-5.6-terra",
"turnIndex": 4,
"hasToolResult": true
},
"response": {
"toolCalls": [
{
"name": "computer_read",
"arguments": "{}",
"id": "call_TkTm7ggRQkAbACpKn2ammmlx"
}
]
},
"recordedTimings": {
"ttftMs": 724,
"interChunkDelaysMs": [
2,
545,
3,
189,
8,
194
],
"totalDurationMs": 1665
},
"metadata": {
"systemHash": "b244db5b",
"toolsHash": "88b34f59"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"fixtures": [
{
"match": {
"userMessage": "Open http://host.docker.internal:46600/shop/tomato and place the order for the tomato seeds. Then tell me the order number in one short sentence.",
"model": "gpt-5.6-terra",
"turnIndex": 5,
"hasToolResult": true
},
"response": {
"content": "Your tomato-seed order number is **FH-2041**."
},
"recordedTimings": {
"ttftMs": 863,
"interChunkDelaysMs": [
39,
387,
6,
0,
4,
26,
0,
3,
0,
26,
6,
3,
4,
0,
1,
0,
0,
157,
2,
0,
196
],
"totalDurationMs": 1723
},
"metadata": {
"systemHash": "b244db5b",
"toolsHash": "88b34f59"
}
}
]
}
Loading
Loading