oomi-ai 0.2.2 → 0.2.3
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/README.md +8 -5
- package/agent_instructions.md +7 -2
- package/bin/oomi-ai.js +101 -14
- package/package.json +1 -1
- package/skills/oomi/agent_instructions.md +7 -2
package/README.md
CHANGED
|
@@ -49,12 +49,15 @@ oomi openclaw pair --app-url https://your-oomi-app.vercel.app --device-id my-ope
|
|
|
49
49
|
`--app-url` must be reachable from the OpenClaw host. If OpenClaw runs on a different machine/network, do not use `localhost` unless tunneled.
|
|
50
50
|
|
|
51
51
|
This prints:
|
|
52
|
-
- `
|
|
53
|
-
- `Connect URL: https://.../?connect=managed://<device-id>&sessionKey=...`
|
|
52
|
+
- `Auth invite URL: https://.../connect/<single-use-token>`
|
|
54
53
|
- A copy-ready block for the user:
|
|
55
54
|
- `Oomi Connect Ready`
|
|
56
|
-
- `
|
|
57
|
-
|
|
55
|
+
- `Auth Link: ...`
|
|
56
|
+
|
|
57
|
+
If you need a fresh auth link later (without re-pairing), run:
|
|
58
|
+
```
|
|
59
|
+
oomi openclaw invite --app-url https://your-oomi-app.vercel.app
|
|
60
|
+
```
|
|
58
61
|
|
|
59
62
|
Agent-intent mapping (recommended):
|
|
60
63
|
- If user says `Connect yourself to Oomi. Use app URL https://www.oomi.ai.`
|
|
@@ -68,7 +71,7 @@ Agent-intent mapping (recommended):
|
|
|
68
71
|
|
|
69
72
|
Important distinction:
|
|
70
73
|
- `pairCode` is one-time and used internally by the pair/bootstrap flow.
|
|
71
|
-
-
|
|
74
|
+
- Invite auth links are the required user flow.
|
|
72
75
|
|
|
73
76
|
Sync personas from the repo into the backend registry:
|
|
74
77
|
```
|
package/agent_instructions.md
CHANGED
|
@@ -31,7 +31,12 @@ If the user asks to connect OpenClaw to Oomi voice/web:
|
|
|
31
31
|
- Example: `oomi openclaw pair --app-url <URL> --no-start`
|
|
32
32
|
8. Return this exact result format to the user:
|
|
33
33
|
- `Oomi Connect Ready`
|
|
34
|
-
- `
|
|
35
|
-
-
|
|
34
|
+
- `Auth Link: ...`
|
|
35
|
+
- No extra narrative text before or after those lines.
|
|
36
|
+
|
|
37
|
+
Primary UX requirement:
|
|
38
|
+
- Never ask the user to enter raw pairing identifiers.
|
|
39
|
+
- The user should open the auth link, complete sign-in, and land directly in connected chat.
|
|
40
|
+
- Return `/connect/<invite-token>` auth links only.
|
|
36
41
|
|
|
37
42
|
Do not ask users to paste gateway IP/token/password when managed connect is available.
|
package/bin/oomi-ai.js
CHANGED
|
@@ -142,6 +142,9 @@ Commands:
|
|
|
142
142
|
openclaw pair
|
|
143
143
|
Pair this OpenClaw host with Oomi and start bridge (single command).
|
|
144
144
|
|
|
145
|
+
openclaw invite
|
|
146
|
+
Create a single-use auth invite link for the paired OpenClaw device.
|
|
147
|
+
|
|
145
148
|
openclaw plugin
|
|
146
149
|
Print OpenClaw extension install/config guidance for Oomi channel plugin.
|
|
147
150
|
|
|
@@ -158,7 +161,7 @@ Common flags:
|
|
|
158
161
|
--broker-http URL Managed broker HTTPS URL (for pair claim)
|
|
159
162
|
--broker-ws URL Managed broker device WS URL (wss://.../cable)
|
|
160
163
|
--pair-code CODE One-time pairing code from Oomi
|
|
161
|
-
--app-url URL Oomi app URL used for pairing APIs (default: http://127.0.0.1:
|
|
164
|
+
--app-url URL Oomi app URL used for pairing APIs (default: http://127.0.0.1:3456)
|
|
162
165
|
--label TEXT Pairing label shown in broker logs
|
|
163
166
|
--session-key KEY Session key used in generated connect URL
|
|
164
167
|
--detach Start bridge in background and exit
|
|
@@ -595,6 +598,25 @@ async function requestManagedPairCode({ appUrl, label }) {
|
|
|
595
598
|
return payload;
|
|
596
599
|
}
|
|
597
600
|
|
|
601
|
+
async function requestConnectInviteLink({ backendHttp, appUrl, sessionKey, deviceToken }) {
|
|
602
|
+
const response = await fetch(`${backendHttp.replace(/\/$/, '')}/v1/invite_links/start`, {
|
|
603
|
+
method: 'POST',
|
|
604
|
+
headers: {
|
|
605
|
+
'Content-Type': 'application/json',
|
|
606
|
+
Authorization: `Bearer ${deviceToken}`,
|
|
607
|
+
},
|
|
608
|
+
body: JSON.stringify({ appUrl, sessionKey }),
|
|
609
|
+
});
|
|
610
|
+
const payload = await response.json().catch(() => ({}));
|
|
611
|
+
if (!response.ok || !payload?.inviteUrl) {
|
|
612
|
+
const message =
|
|
613
|
+
(payload && typeof payload.error === 'string' && payload.error) ||
|
|
614
|
+
`Invite link start failed (${response.status})`;
|
|
615
|
+
throw new Error(message);
|
|
616
|
+
}
|
|
617
|
+
return payload;
|
|
618
|
+
}
|
|
619
|
+
|
|
598
620
|
async function fetchManagedGatewayConfig({ appUrl }) {
|
|
599
621
|
const baseUrl = appUrl.replace(/\/$/, '');
|
|
600
622
|
const response = await fetch(`${baseUrl}/api/gateway/managed/config`, {
|
|
@@ -924,7 +946,7 @@ async function startOpenclawBridge(flags) {
|
|
|
924
946
|
|
|
925
947
|
async function pairAndStartOpenclawBridge(flags) {
|
|
926
948
|
const bridgeState = readBridgeState();
|
|
927
|
-
const appUrl = String(flags['app-url'] || process.env.OOMI_APP_URL || 'http://127.0.0.1:
|
|
949
|
+
const appUrl = String(flags['app-url'] || process.env.OOMI_APP_URL || 'http://127.0.0.1:3456').trim();
|
|
928
950
|
const deviceId = resolveDeviceId(flags, bridgeState);
|
|
929
951
|
const label = String(flags.label || `${deviceId}-bridge`).trim();
|
|
930
952
|
const sessionKey = String(
|
|
@@ -961,19 +983,24 @@ async function pairAndStartOpenclawBridge(flags) {
|
|
|
961
983
|
brokerWs,
|
|
962
984
|
deviceId,
|
|
963
985
|
deviceToken,
|
|
986
|
+
sessionKey,
|
|
964
987
|
claimedAt: new Date().toISOString(),
|
|
965
988
|
expiresAt: claimed.expiresAt || null,
|
|
966
989
|
});
|
|
967
990
|
|
|
968
|
-
const
|
|
969
|
-
|
|
970
|
-
|
|
991
|
+
const invite = await requestConnectInviteLink({
|
|
992
|
+
backendHttp: managedConfig.brokerHttpUrl,
|
|
993
|
+
appUrl,
|
|
994
|
+
sessionKey,
|
|
995
|
+
deviceToken,
|
|
996
|
+
});
|
|
997
|
+
const inviteUrl = String(invite.inviteUrl || '').trim();
|
|
998
|
+
const inviteExpiresAt = String(invite.expiresAt || '').trim();
|
|
971
999
|
|
|
972
1000
|
const pairSummary = {
|
|
973
1001
|
deviceId,
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
connectUrl,
|
|
1002
|
+
inviteUrl,
|
|
1003
|
+
inviteExpiresAt,
|
|
977
1004
|
brokerHttpUrl: managedConfig.brokerHttpUrl,
|
|
978
1005
|
brokerDeviceWsUrl: brokerWs,
|
|
979
1006
|
bridgeMode: shouldStart ? (detach ? 'detached' : 'attached') : 'skipped',
|
|
@@ -984,15 +1011,15 @@ async function pairAndStartOpenclawBridge(flags) {
|
|
|
984
1011
|
console.log(JSON.stringify(pairSummary, null, 2));
|
|
985
1012
|
} else {
|
|
986
1013
|
console.log(`Paired device: ${deviceId}`);
|
|
987
|
-
console.log(`
|
|
988
|
-
|
|
989
|
-
|
|
1014
|
+
console.log(`Auth invite URL: ${inviteUrl}`);
|
|
1015
|
+
if (inviteExpiresAt) {
|
|
1016
|
+
console.log(`Invite expires at: ${inviteExpiresAt}`);
|
|
1017
|
+
}
|
|
990
1018
|
console.log('');
|
|
991
|
-
console.log('Share this with the user:');
|
|
1019
|
+
console.log('Share this exact response with the user (no extra text):');
|
|
992
1020
|
console.log('----------------------------------------');
|
|
993
1021
|
console.log('Oomi Connect Ready');
|
|
994
|
-
console.log(`
|
|
995
|
-
console.log(`Link: ${connectUrl}`);
|
|
1022
|
+
console.log(`Auth Link: ${inviteUrl}`);
|
|
996
1023
|
console.log('----------------------------------------');
|
|
997
1024
|
}
|
|
998
1025
|
|
|
@@ -1033,6 +1060,61 @@ async function pairAndStartOpenclawBridge(flags) {
|
|
|
1033
1060
|
});
|
|
1034
1061
|
}
|
|
1035
1062
|
|
|
1063
|
+
async function createOpenclawInviteLink(flags) {
|
|
1064
|
+
const bridgeState = readBridgeState();
|
|
1065
|
+
const backendHttp = String(
|
|
1066
|
+
flags['backend-url'] ||
|
|
1067
|
+
flags['broker-http'] ||
|
|
1068
|
+
process.env.OOMI_BACKEND_URL ||
|
|
1069
|
+
process.env.OOMI_CHAT_BROKER_HTTP_URL ||
|
|
1070
|
+
bridgeState.brokerHttp ||
|
|
1071
|
+
''
|
|
1072
|
+
).trim();
|
|
1073
|
+
const appUrl = String(flags['app-url'] || process.env.OOMI_APP_URL || 'http://127.0.0.1:3456').trim();
|
|
1074
|
+
const sessionKey = String(
|
|
1075
|
+
flags['session-key'] ||
|
|
1076
|
+
process.env.OOMI_SESSION_KEY ||
|
|
1077
|
+
bridgeState.sessionKey ||
|
|
1078
|
+
'agent:main:webchat:channel:oomi'
|
|
1079
|
+
).trim();
|
|
1080
|
+
const deviceToken = String(flags['device-token'] || bridgeState.deviceToken || '').trim();
|
|
1081
|
+
const jsonOutput = isTruthyFlag(flags.json);
|
|
1082
|
+
|
|
1083
|
+
if (!backendHttp) {
|
|
1084
|
+
throw new Error('Missing backend URL. Set --backend-url (or --broker-http) or pair first.');
|
|
1085
|
+
}
|
|
1086
|
+
if (!deviceToken) {
|
|
1087
|
+
throw new Error('Missing device token in bridge state. Run: oomi openclaw pair --app-url https://www.oomi.ai --no-start');
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
const invite = await requestConnectInviteLink({
|
|
1091
|
+
backendHttp,
|
|
1092
|
+
appUrl,
|
|
1093
|
+
sessionKey,
|
|
1094
|
+
deviceToken,
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
const summary = {
|
|
1098
|
+
appUrl,
|
|
1099
|
+
backendHttp,
|
|
1100
|
+
inviteUrl: invite.inviteUrl,
|
|
1101
|
+
expiresAt: invite.expiresAt || null,
|
|
1102
|
+
sessionKey,
|
|
1103
|
+
};
|
|
1104
|
+
|
|
1105
|
+
if (jsonOutput) {
|
|
1106
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
1107
|
+
return;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
console.log('Oomi Auth Invite Ready');
|
|
1111
|
+
console.log('----------------------');
|
|
1112
|
+
console.log(`Auth Link: ${summary.inviteUrl}`);
|
|
1113
|
+
if (summary.expiresAt) {
|
|
1114
|
+
console.log(`Expires: ${summary.expiresAt}`);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1036
1118
|
function printOpenclawPluginSetup(flags) {
|
|
1037
1119
|
const bridgeState = readBridgeState();
|
|
1038
1120
|
const backendUrl = String(
|
|
@@ -1141,6 +1223,11 @@ async function main() {
|
|
|
1141
1223
|
return;
|
|
1142
1224
|
}
|
|
1143
1225
|
|
|
1226
|
+
if (command === 'openclaw' && subcommand === 'invite') {
|
|
1227
|
+
await createOpenclawInviteLink(args.flags);
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1144
1231
|
if (command === 'openclaw' && subcommand === 'plugin') {
|
|
1145
1232
|
printOpenclawPluginSetup(args.flags);
|
|
1146
1233
|
return;
|
package/package.json
CHANGED
|
@@ -31,7 +31,12 @@ If the user asks to connect OpenClaw to Oomi voice/web:
|
|
|
31
31
|
- Example: `oomi openclaw pair --app-url <URL> --no-start`
|
|
32
32
|
8. Return this exact result format to the user:
|
|
33
33
|
- `Oomi Connect Ready`
|
|
34
|
-
- `
|
|
35
|
-
-
|
|
34
|
+
- `Auth Link: ...`
|
|
35
|
+
- No extra narrative text before or after those lines.
|
|
36
|
+
|
|
37
|
+
Primary UX requirement:
|
|
38
|
+
- Never ask the user to enter raw pairing identifiers.
|
|
39
|
+
- The user should open the auth link, complete sign-in, and land directly in connected chat.
|
|
40
|
+
- Return `/connect/<invite-token>` auth links only.
|
|
36
41
|
|
|
37
42
|
Do not ask users to paste gateway IP/token/password when managed connect is available.
|