oomi-ai 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent_instructions.md +4 -0
- package/bin/oomi-ai.js +18 -5
- package/lib/agentChannels.js +52 -3
- package/lib/gatewayProbe.js +6 -1
- package/lib/localAgent.js +5 -1
- package/lib/runtimeFailure.js +43 -0
- package/package.json +3 -2
- package/skills/oomi/SKILL.md +4 -0
- package/skills/oomi/agent_instructions.md +4 -0
package/agent_instructions.md
CHANGED
|
@@ -142,6 +142,10 @@ Use this when your owner asks you to let another agent (Claude, Codex, a Grok bo
|
|
|
142
142
|
|
|
143
143
|
To review a channel, use `oomi channel list` and `oomi channel show ID`.
|
|
144
144
|
|
|
145
|
+
**When you can't answer.** Your AI provider might reject your sign-in, hit a limit or be unreachable. If so, oomi records the reason, tells your owner what to fix and tells the other side the message wasn't answered. Tell your owner plainly which AI provider failed and what it said. Ask them to sign in again on this computer themselves, in a terminal or the provider's app here. Never ask them to paste passwords or one-time codes into a chat. `oomi verify --connection NAME` checks that you can answer again. `oomi channel create` also returns `warnings` when your bridge can't answer; tell your owner before they share the link.
|
|
146
|
+
|
|
147
|
+
**Use your own connection.** Turns started by the bridge already use it. Otherwise, pass `--connection NAME` (`oomi bridge list` shows the names). If oomi says it used a connection that isn't linked, rerun with your own. Don't create a new Auth Link unless your owner asked to connect you.
|
|
148
|
+
|
|
145
149
|
To join another agent's link as a guest:
|
|
146
150
|
|
|
147
151
|
1. Run `oomi channel join LINK`.
|
package/bin/oomi-ai.js
CHANGED
|
@@ -20,6 +20,7 @@ import { handleSpacesCommand, compactHealth } from '../lib/spaces.js';
|
|
|
20
20
|
import { handleObjectivesCommand } from '../lib/objectives.js';
|
|
21
21
|
import { handleRoutinesCommand, startRoutineEventWorker } from '../lib/routines.js';
|
|
22
22
|
import { handleChannelCommand, startAgentChannelWorker } from '../lib/agentChannels.js';
|
|
23
|
+
import { classifyRuntimeFailure } from '../lib/runtimeFailure.js';
|
|
23
24
|
import { createPersonaApiClient } from '../lib/personaApiClient.js';
|
|
24
25
|
import { inferSpokenMetadataFromContent, normalizeSpokenMetadata } from '../lib/spokenMetadata.js';
|
|
25
26
|
import {
|
|
@@ -2650,7 +2651,9 @@ async function startOpenclawBridge(flags) {
|
|
|
2650
2651
|
state: { ...bridgeState, brokerHttp, deviceToken },
|
|
2651
2652
|
connection: bridgeConnectionName,
|
|
2652
2653
|
deliver: deliverAgentEvent,
|
|
2653
|
-
onError: (error) => updateBridgeStatus({ agentChannelError:
|
|
2654
|
+
onError: (error) => updateBridgeStatus({ agentChannelError: error.failure
|
|
2655
|
+
? `Couldn't answer a chat-link message: ${error.failure.summary}. ${error.failure.hint}`
|
|
2656
|
+
: `Agent channel delivery: ${error.message}` }),
|
|
2654
2657
|
onDelivered: () => updateBridgeStatus({ agentChannelError: '' }),
|
|
2655
2658
|
});
|
|
2656
2659
|
console.log(`Local gateway: ${gateway.gatewayUrl}`);
|
|
@@ -4450,6 +4453,14 @@ function connectionDirectory() {
|
|
|
4450
4453
|
return path.join(process.env.OOMI_CONNECTIONS_DIR || path.join(os.homedir(), '.oomi', 'connections'), bridgeConnectionName);
|
|
4451
4454
|
}
|
|
4452
4455
|
|
|
4456
|
+
// A failed connection check usually means the agent's own AI access is broken.
|
|
4457
|
+
// Say that plainly, with the fix, instead of a bare runtime error.
|
|
4458
|
+
function explainVerificationFailure(err) {
|
|
4459
|
+
const failure = classifyRuntimeFailure(err);
|
|
4460
|
+
if (failure.code === 'runtime_failed') return err;
|
|
4461
|
+
return Object.assign(new Error(`This agent couldn't answer the connection check: ${failure.summary}. ${failure.hint} Oomi itself is fine; nothing else needs reconnecting. (Details: ${failure.detail})`), { failure });
|
|
4462
|
+
}
|
|
4463
|
+
|
|
4453
4464
|
async function verifyLocalAgent(state) {
|
|
4454
4465
|
if (state.openclawHome) process.env.OPENCLAW_HOME = state.openclawHome;
|
|
4455
4466
|
let result;
|
|
@@ -4519,8 +4530,9 @@ async function connectLocalAgent(flags) {
|
|
|
4519
4530
|
const verified = await verifyLocalAgent(state);
|
|
4520
4531
|
state.verifiedAt = verified.verifiedAt;
|
|
4521
4532
|
} catch (err) {
|
|
4522
|
-
|
|
4523
|
-
|
|
4533
|
+
const explained = explainVerificationFailure(err);
|
|
4534
|
+
updateBridgeStatus({ runtime, runtimeReady: false, status: 'degraded', lastErrorMessage: explained.message });
|
|
4535
|
+
throw explained;
|
|
4524
4536
|
}
|
|
4525
4537
|
} else {
|
|
4526
4538
|
console.log(`Reusing the verified ${runtime} runtime. No model test message sent. Use oomi verify for an explicit paid-model probe.`);
|
|
@@ -4676,8 +4688,9 @@ async function main() {
|
|
|
4676
4688
|
updateBridgeStatus({ runtimeReady: true, verifiedAt: result.verifiedAt, lastErrorMessage: '' });
|
|
4677
4689
|
console.log(JSON.stringify(result, null, 2));
|
|
4678
4690
|
} catch (err) {
|
|
4679
|
-
|
|
4680
|
-
|
|
4691
|
+
const explained = explainVerificationFailure(err);
|
|
4692
|
+
updateBridgeStatus({ runtimeReady: false, status: 'degraded', lastErrorMessage: explained.message });
|
|
4693
|
+
throw explained;
|
|
4681
4694
|
}
|
|
4682
4695
|
return;
|
|
4683
4696
|
}
|
package/lib/agentChannels.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { randomUUID } from 'node:crypto';
|
|
4
5
|
import { readJson, writePrivateJson } from './localAgent.js';
|
|
6
|
+
import { classifyRuntimeFailure } from './runtimeFailure.js';
|
|
5
7
|
|
|
6
8
|
// Owner-visible conversations between this agent and one other agent.
|
|
7
9
|
// Host side uses the device token against the Oomi API. Guest side (after
|
|
@@ -42,6 +44,46 @@ export function parseChannelLink(link) {
|
|
|
42
44
|
return { origin: url.origin, token: match[1] };
|
|
43
45
|
}
|
|
44
46
|
|
|
47
|
+
function connectionsRoot() {
|
|
48
|
+
return process.env.OOMI_CONNECTIONS_DIR || path.join(os.homedir(), '.oomi', 'connections');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function localConnections() {
|
|
52
|
+
try {
|
|
53
|
+
return fs.readdirSync(connectionsRoot(), { withFileTypes: true })
|
|
54
|
+
.filter((entry) => entry.isDirectory() && fs.existsSync(path.join(connectionsRoot(), entry.name, 'oomi-bridge.json')))
|
|
55
|
+
.map((entry) => entry.name);
|
|
56
|
+
} catch { return []; }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Agents that ran a command without --connection were sent to a stale default
|
|
60
|
+
// connection and then created Auth Links for it. Say which connection was used
|
|
61
|
+
// and which others exist, and steer away from reconnecting.
|
|
62
|
+
export function explainConnectionError(error, directory) {
|
|
63
|
+
const notLinked = error?.status === 403 && /not linked/i.test(error.message || '');
|
|
64
|
+
const missing = /Connect this agent to Oomi first/.test(error?.message || '');
|
|
65
|
+
if (!notLinked && !missing) return error;
|
|
66
|
+
const named = directory && path.resolve(path.dirname(directory)) === path.resolve(connectionsRoot());
|
|
67
|
+
const label = named ? `the connection "${path.basename(directory)}"` : 'the default OpenClaw connection';
|
|
68
|
+
const others = localConnections().filter((name) => !named || name !== path.basename(directory));
|
|
69
|
+
const problem = missing ? `found no saved login for ${label}` : `used ${label}, but that connection isn't linked to an oomi account`;
|
|
70
|
+
const next = others.length
|
|
71
|
+
? `Connections on this computer: ${others.join(', ')}. If one of them is you, rerun with --connection NAME.`
|
|
72
|
+
: 'No other oomi connections were found on this computer.';
|
|
73
|
+
return Object.assign(new Error(`oomi ${problem}. ${next} Don't create a new Auth Link or reconnect unless your owner asked to connect this agent.`), { status: error.status, reasonCode: error.reasonCode });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// A link only helps if this agent can answer; warn before handing one out.
|
|
77
|
+
export function bridgeWarnings(directory) {
|
|
78
|
+
if (!directory) return [];
|
|
79
|
+
const status = readJson(path.join(directory, 'oomi-bridge-status.json'), null);
|
|
80
|
+
if (!status) return ['No oomi bridge status was found for this connection. Run oomi bridge repair for it, or guest messages will wait unanswered.'];
|
|
81
|
+
const warnings = [];
|
|
82
|
+
if (['error', 'degraded', 'failed', 'stopped'].includes(status.status)) warnings.push(`Your oomi bridge reports "${status.status}"${status.lastErrorMessage ? `: ${String(status.lastErrorMessage).replace(/\.\s*$/, '')}` : ''}.`);
|
|
83
|
+
if (status.agentChannelError) warnings.push(status.agentChannelError);
|
|
84
|
+
return warnings;
|
|
85
|
+
}
|
|
86
|
+
|
|
45
87
|
function guestRecordPath(directory, channelId) {
|
|
46
88
|
return path.join(directory, 'agent-channels', `${channelId}.json`);
|
|
47
89
|
}
|
|
@@ -90,7 +132,10 @@ function optionalInteger(value, name) {
|
|
|
90
132
|
return number;
|
|
91
133
|
}
|
|
92
134
|
|
|
93
|
-
export async function handleChannelCommand(state, action, flags = {}, positionals = [], { directory, request = channelRequest, guest = guestRequest, print = (value) => console.log(JSON.stringify(value, null, 2)) } = {}) {
|
|
135
|
+
export async function handleChannelCommand(state, action, flags = {}, positionals = [], { directory, request: rawRequest = channelRequest, guest = guestRequest, print = (value) => console.log(JSON.stringify(value, null, 2)) } = {}) {
|
|
136
|
+
const request = async (...args) => {
|
|
137
|
+
try { return await rawRequest(...args); } catch (error) { throw explainConnectionError(error, directory); }
|
|
138
|
+
};
|
|
94
139
|
const id = positionals[0] || flags.id;
|
|
95
140
|
const requireId = () => { if (typeof id !== 'string' || !CHANNEL_ID.test(id)) throw new Error('Provide a channel ID (ach_...) from oomi channel list.'); };
|
|
96
141
|
let result;
|
|
@@ -111,6 +156,8 @@ export async function handleChannelCommand(state, action, flags = {}, positional
|
|
|
111
156
|
result = { ...result, next: audience === 'person'
|
|
112
157
|
? 'Give your owner both links: the chat link to send to the person, and the watchUrl where they read along, approve requests and end the chat. The person\'s messages arrive as separate Oomi chat turns; your reply text goes back to them.'
|
|
113
158
|
: 'Give this link to your owner to pass to the other agent. That agent joins from wherever it runs; do not start, install, sign in to or message it yourself, and never ask your owner for sign-in codes for it. Its messages arrive as separate Oomi channel turns; your reply text goes back to it. Your owner can watch and end the channel in Oomi.' };
|
|
159
|
+
const warnings = bridgeWarnings(directory);
|
|
160
|
+
if (warnings.length) result.warnings = [...warnings, 'Tell your owner about these before they share the link: the other side\'s messages will not be answered until they are fixed.'];
|
|
114
161
|
break;
|
|
115
162
|
}
|
|
116
163
|
case 'list': {
|
|
@@ -244,8 +291,10 @@ export function startAgentChannelWorker({ state, deliver, connection = '', reque
|
|
|
244
291
|
try {
|
|
245
292
|
reply = await deliver({ sessionKey: item.sessionKey, idempotencyKey: item.messageId, message: channelTurnMessage(item, connection), retryInterrupted: false });
|
|
246
293
|
} catch (error) {
|
|
247
|
-
|
|
248
|
-
|
|
294
|
+
// Report why, so the owner is told what to fix and the guest isn't left guessing.
|
|
295
|
+
const failure = classifyRuntimeFailure(error);
|
|
296
|
+
await request(state, `agent_channels/inbox/${item.messageId}/ack`, { method: 'POST', body: { outcome: 'failed', failureCode: failure.code, failureDetail: failure.detail } }).catch(() => {});
|
|
297
|
+
onError(Object.assign(error, { failure }));
|
|
249
298
|
continue;
|
|
250
299
|
}
|
|
251
300
|
const text = typeof reply?.text === 'string' ? reply.text.trim() : '';
|
package/lib/gatewayProbe.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import WebSocket from 'ws';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { redactDetail } from './runtimeFailure.js';
|
|
3
4
|
|
|
4
5
|
// The broker's protocol is independent of the installed local gateway version.
|
|
5
6
|
export const LOCAL_PROTOCOL_MIN = 3;
|
|
@@ -48,7 +49,11 @@ export function probeGateway({ gateway, deviceIdentity, prepareFrame, verifyRepl
|
|
|
48
49
|
message: turn?.message || 'Oomi connection check. Reply with OOMI_OK only. Do not use tools or change anything.',
|
|
49
50
|
} }));
|
|
50
51
|
} else if (verifyReply && frame.event === 'chat' && frame.payload?.runId === runId) {
|
|
51
|
-
if (frame.payload.state === 'error' || frame.payload.state === 'aborted')
|
|
52
|
+
if (frame.payload.state === 'error' || frame.payload.state === 'aborted') {
|
|
53
|
+
// Keep the runtime's own reason (for example a rejected model login) so callers can say what went wrong.
|
|
54
|
+
const reason = redactDetail(frame.payload.errorMessage || frame.payload.error?.message || frame.payload.state);
|
|
55
|
+
return finish(Object.assign(new Error(`Local agent could not complete the message: ${reason}`), { runtimeDetail: reason }));
|
|
56
|
+
}
|
|
52
57
|
if (frame.payload.state === 'final') {
|
|
53
58
|
const content = frame.payload.message?.content;
|
|
54
59
|
const text = typeof content === 'string' ? content : (Array.isArray(content) ? content.map((part) => part.text || '').join('') : '');
|
package/lib/localAgent.js
CHANGED
|
@@ -7,6 +7,7 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
7
7
|
import { runSharedHermesTurn, hermesRefusal } from './hermesGateway.js';
|
|
8
8
|
import { runHermesAcpTurn, hermesAcpAvailable, resetHermesAcp, warmHermesAcp } from './hermesAcp.js';
|
|
9
9
|
import { grokbotConfig, runGrokbotTurn, completedGrokbotTurn } from './grokbotRuntime.js';
|
|
10
|
+
import { classifyRuntimeFailure } from './runtimeFailure.js';
|
|
10
11
|
|
|
11
12
|
const IMAGE_EXTENSIONS = { 'image/jpeg': '.jpg', 'image/png': '.png', 'image/webp': '.webp', 'image/gif': '.gif' };
|
|
12
13
|
const MAX_IMAGE_BYTES = 10 * 1024 * 1024;
|
|
@@ -194,7 +195,10 @@ function runAgentProcess(config, request, { signal, timeoutMs = 180000 } = {}) {
|
|
|
194
195
|
if (error) return reject(error);
|
|
195
196
|
if (code !== 0) {
|
|
196
197
|
const reason = config.runtime === 'hermes' && code === 1 && !diagnosticsTruncated && !output.trim() && diagnostics.match(/^hermes-refusal-reason:\s*([A-Z_]+)(?:\r?\n|$)/)?.[1];
|
|
197
|
-
|
|
198
|
+
// stderr can hold private tool output, so it never enters the message. Keep
|
|
199
|
+
// only the kind of failure its last lines show, such as a rejected provider login.
|
|
200
|
+
const runtimeFailureCode = classifyRuntimeFailure({ message: diagnostics.trim().split(/\r?\n/).slice(-3).join(' ') }).code;
|
|
201
|
+
return reject(hermesRefusal(reason) || Object.assign(new Error(`Agent exited with code ${code}. Check local runtime credentials and logs.`), { runtimeFailureCode }));
|
|
198
202
|
}
|
|
199
203
|
try {
|
|
200
204
|
const result = config.runtime === 'hermes'
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Turns a raw agent-runtime error into something an agent, its owner and a
|
|
2
|
+
// guest can act on. The raw text stays on this computer except for a short,
|
|
3
|
+
// redacted excerpt sent to the owner.
|
|
4
|
+
|
|
5
|
+
const RULES = [
|
|
6
|
+
['model_auth_failed', /\b401\b|\b403\b|unauthori[sz]ed|authenticat|invalid[ _-]?(x-)?api[ _-]?key|api key|oauth|access token|refresh token|token (has )?expired|expired token|not logged in|log ?in again|sign ?in again|please (log|sign) ?in|login (was )?rejected|invalid credentials|credentials? (are |were |have )?(invalid|expired|rejected)/i],
|
|
7
|
+
['model_rate_limited', /\b429\b|rate[ _-]?limit|quota|usage limit|too many requests/i],
|
|
8
|
+
['model_unavailable', /\b5\d\d\b|overloaded|unavailable|ECONNREFUSED|ENOTFOUND|ETIMEDOUT|ECONNRESET|network|could not reach/i],
|
|
9
|
+
['runtime_timeout', /timed out|timeout/i],
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export const FAILURE_SUMMARIES = {
|
|
13
|
+
model_auth_failed: 'its AI provider rejected its sign-in',
|
|
14
|
+
model_rate_limited: 'its AI provider hit a usage or rate limit',
|
|
15
|
+
model_unavailable: "its AI provider couldn't be reached",
|
|
16
|
+
runtime_timeout: 'it took too long to answer',
|
|
17
|
+
runtime_failed: 'its agent runtime stopped with an error',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const FAILURE_HINTS = {
|
|
21
|
+
model_auth_failed: "Ask your owner to sign in to your AI provider again on this computer themselves (in a terminal or the provider's app here). Never ask them to paste passwords or one-time codes into a chat.",
|
|
22
|
+
model_rate_limited: 'Wait for the provider limit to reset, or ask your owner to raise it.',
|
|
23
|
+
model_unavailable: 'Check this computer is online and the provider is up, then try again.',
|
|
24
|
+
runtime_timeout: 'Try again with a shorter request, or check the agent runtime is responsive.',
|
|
25
|
+
runtime_failed: 'Check the agent runtime logs on this computer, then try again.',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function redactDetail(text, limit = 300) {
|
|
29
|
+
return String(text || '')
|
|
30
|
+
.replace(/Bearer\s+\S+/gi, 'Bearer [redacted]')
|
|
31
|
+
.replace(/\b(sk|pk|rk|oomi_gst|xox[abpr])[-_][A-Za-z0-9_-]{6,}/g, '[redacted]')
|
|
32
|
+
.replace(/[A-Za-z0-9_\-+/=]{32,}/g, '[redacted]')
|
|
33
|
+
.replace(/\s+/g, ' ')
|
|
34
|
+
.trim()
|
|
35
|
+
.slice(-limit);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function classifyRuntimeFailure(error) {
|
|
39
|
+
const raw = [error?.runtimeDetail, error?.message, typeof error === 'string' ? error : ''].filter(Boolean).join(' | ');
|
|
40
|
+
// A runtime that can't share its output (stderr may be private) passes only the code.
|
|
41
|
+
const code = FAILURE_SUMMARIES[error?.runtimeFailureCode] ? error.runtimeFailureCode : (RULES.find(([, pattern]) => pattern.test(raw)) || ['runtime_failed'])[0];
|
|
42
|
+
return { code, summary: FAILURE_SUMMARIES[code], hint: FAILURE_HINTS[code], detail: redactDetail(raw) };
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oomi-ai",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "Connect OpenClaw, Hermes, Grok Bot, and other agents to Oomi with verified runtime adapters",
|
|
5
5
|
"bin": {
|
|
6
6
|
"oomi": "bin/oomi-ai.js"
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"url": "https://github.com/crispcode-io/oomi/issues"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
|
-
"check": "node --check bin/oomi-ai.js && node --check lib/bridgeService.js && node --check lib/bridgeMaintenance.js && node --check lib/localAgent.js && node --check lib/hermesGateway.js && node --check lib/hermesAcp.js && node --check lib/grokbotRuntime.js && node --check lib/connectionSetup.js && node --check lib/processSupervisor.js && node --check lib/agentChannels.js",
|
|
52
|
+
"check": "node --check bin/oomi-ai.js && node --check lib/bridgeService.js && node --check lib/bridgeMaintenance.js && node --check lib/localAgent.js && node --check lib/hermesGateway.js && node --check lib/hermesAcp.js && node --check lib/grokbotRuntime.js && node --check lib/connectionSetup.js && node --check lib/processSupervisor.js && node --check lib/agentChannels.js && node --check lib/runtimeFailure.js",
|
|
53
53
|
"test": "node --test test/*.test.mjs"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"lib/connectionSetup.js",
|
|
86
86
|
"lib/processSupervisor.js",
|
|
87
87
|
"lib/agentChannels.js",
|
|
88
|
+
"lib/runtimeFailure.js",
|
|
88
89
|
"skills/oomi-delivery/SKILL.md"
|
|
89
90
|
]
|
|
90
91
|
}
|
package/skills/oomi/SKILL.md
CHANGED
|
@@ -168,6 +168,10 @@ Use this when your owner asks you to let another agent (Claude, Codex, a Grok bo
|
|
|
168
168
|
|
|
169
169
|
To review a channel, use `oomi channel list` and `oomi channel show ID`.
|
|
170
170
|
|
|
171
|
+
**When you can't answer.** Your AI provider might reject your sign-in, hit a limit or be unreachable. If so, oomi records the reason, tells your owner what to fix and tells the other side the message wasn't answered. Tell your owner plainly which AI provider failed and what it said. Ask them to sign in again on this computer themselves, in a terminal or the provider's app here. Never ask them to paste passwords or one-time codes into a chat. `oomi verify --connection NAME` checks that you can answer again. `oomi channel create` also returns `warnings` when your bridge can't answer; tell your owner before they share the link.
|
|
172
|
+
|
|
173
|
+
**Use your own connection.** Turns started by the bridge already use it. Otherwise, pass `--connection NAME` (`oomi bridge list` shows the names). If oomi says it used a connection that isn't linked, rerun with your own. Don't create a new Auth Link unless your owner asked to connect you.
|
|
174
|
+
|
|
171
175
|
To join another agent's link as a guest:
|
|
172
176
|
|
|
173
177
|
1. Run `oomi channel join LINK`.
|
|
@@ -142,6 +142,10 @@ Use this when your owner asks you to let another agent (Claude, Codex, a Grok bo
|
|
|
142
142
|
|
|
143
143
|
To review a channel, use `oomi channel list` and `oomi channel show ID`.
|
|
144
144
|
|
|
145
|
+
**When you can't answer.** Your AI provider might reject your sign-in, hit a limit or be unreachable. If so, oomi records the reason, tells your owner what to fix and tells the other side the message wasn't answered. Tell your owner plainly which AI provider failed and what it said. Ask them to sign in again on this computer themselves, in a terminal or the provider's app here. Never ask them to paste passwords or one-time codes into a chat. `oomi verify --connection NAME` checks that you can answer again. `oomi channel create` also returns `warnings` when your bridge can't answer; tell your owner before they share the link.
|
|
146
|
+
|
|
147
|
+
**Use your own connection.** Turns started by the bridge already use it. Otherwise, pass `--connection NAME` (`oomi bridge list` shows the names). If oomi says it used a connection that isn't linked, rerun with your own. Don't create a new Auth Link unless your owner asked to connect you.
|
|
148
|
+
|
|
145
149
|
To join another agent's link as a guest:
|
|
146
150
|
|
|
147
151
|
1. Run `oomi channel join LINK`.
|