Skip to content
Open
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
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ jobs:
cache: npm

- run: npm ci

- name: Disable AppArmor
shell: bash
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns

- run: npm test
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,10 @@ If you run into any issues, checkout our [troubleshooting guide](./docs/troubles
- [`get_memory_snapshot_details`](docs/tool-reference.md#get_memory_snapshot_details)
- [`get_nodes_by_class`](docs/tool-reference.md#get_nodes_by_class)
- [`load_memory_snapshot`](docs/tool-reference.md#load_memory_snapshot)
- **Opera** (4 tools)
- **Opera** (5 tools)
- [`opera_chat`](docs/tool-reference.md#opera_chat)
- [`opera_do`](docs/tool-reference.md#opera_do)
- [`opera_list_models`](docs/tool-reference.md#opera_list_models)
- [`opera_make`](docs/tool-reference.md#opera_make)
- [`opera_research`](docs/tool-reference.md#opera_research)
- **Extensions** (5 tools)
Expand Down
12 changes: 11 additions & 1 deletion docs/tool-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@
- [`get_memory_snapshot_details`](#get_memory_snapshot_details)
- [`get_nodes_by_class`](#get_nodes_by_class)
- [`load_memory_snapshot`](#load_memory_snapshot)
- **[Opera](#opera)** (4 tools)
- **[Opera](#opera)** (5 tools)
- [`opera_chat`](#opera_chat)
- [`opera_do`](#opera_do)
- [`opera_list_models`](#opera_list_models)
- [`opera_make`](#opera_make)
- [`opera_research`](#opera_research)
- **[Extensions](#extensions)** (5 tools)
Expand Down Expand Up @@ -500,6 +501,7 @@ in the DevTools Elements panel (if any).
**Parameters:**

- **prompt** (string) **(required)**: The prompt to send to Opera AI.
- **model** (string) _(optional)_: Model ID to use for the chat. Omit to use the browser default. Use [`opera_list_models`](#opera_list_models) to discover available IDs.

---

Expand All @@ -513,6 +515,14 @@ in the DevTools Elements panel (if any).

---

### `opera_list_models`

**Description:** List available AI models for Opera chat. Returns model IDs, display names, and which is the default. Only available when connected to Opera Neon.

**Parameters:** None

---

### `opera_make`

**Description:** Ask Opera's built-in AI to create or generate content and return the result. Only available when connected to Opera Neon.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions src/bin/chrome-devtools-cli-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,13 @@ export const commands: Commands = {
description: 'The prompt to send to Opera AI.',
required: true,
},
model: {
name: 'model',
type: 'string',
description:
'Model ID to use for the chat. Omit to use the browser default. Use opera_list_models to discover available IDs.',
required: false,
},
},
},
opera_do: {
Expand All @@ -492,6 +499,12 @@ export const commands: Commands = {
},
},
},
opera_list_models: {
description:
'List available AI models for Opera chat. Returns model IDs, display names, and which is the default. Only available when connected to Opera Neon.',
category: 'Opera',
args: {},
},
opera_make: {
description:
"Ask Opera's built-in AI to create or generate content and return the result. Only available when connected to Opera Neon.",
Expand Down
8 changes: 8 additions & 0 deletions src/telemetry/tool_call_metrics.json
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,10 @@
{
"name": "prompt_length",
"argType": "number"
},
{
"name": "model_length",
"argType": "number"
}
]
},
Expand Down Expand Up @@ -667,5 +671,9 @@
"argType": "string"
}
]
},
{
"name": "opera_list_models",
"args": []
}
]
40 changes: 37 additions & 3 deletions src/tools/opera.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const getCDPSession = (page: {_client(): CDPSession}): CDPSession =>
page._client();

const MAX_SW_RETRIES = 5;
const SW_RETRY_DELAY_MS = 1000;
const SW_RETRY_DELAY_MS = 2500;

const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

Expand Down Expand Up @@ -129,15 +129,25 @@ export const operaChat = definePageTool({
},
schema: {
prompt: zod.string().describe('The prompt to send to Opera AI.'),
model: zod
.string()
.optional()
.describe(
'Model ID to use for the chat. Omit to use the browser default. Use opera_list_models to discover available IDs.',
),
},
handler: async (request, response) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const session = getCDPSession(request.page.pptrPage as any);
try {
const result = await dispatchAction(session, {
const payload: Record<string, unknown> = {
action: 'chat',
prompt: request.params.prompt,
});
};
if (request.params.model !== undefined) {
payload['model'] = request.params.model;
}
const result = await dispatchAction(session, payload);
response.appendResponseLine(result);
} catch (e) {
response.appendResponseLine(
Expand Down Expand Up @@ -261,3 +271,27 @@ export const operaResearch = definePageTool({
}
},
});

export const operaListModels = definePageTool({
name: 'opera_list_models',
description:
'List available AI models for Opera chat. Returns model IDs, display names, and which is the default. Only available when connected to Opera Neon.',
blockedByDialog: false,
annotations: {
category: ToolCategory.OPERA,
readOnlyHint: true,
},
schema: {},
handler: async (request, response) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const session = getCDPSession(request.page.pptrPage as any);
try {
const result = await dispatchAction(session, {action: 'listModels'});
response.appendResponseLine(result);
} catch (e) {
response.appendResponseLine(
`Opera.dispatchAction(listModels) failed with error: ${(e as Error).message}`,
);
}
},
});
Loading