oomi-ai 0.2.18 → 0.2.19

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 CHANGED
@@ -4,8 +4,9 @@ OpenClaw channel plugin and bridge tooling for Oomi managed chat and voice.
4
4
 
5
5
  ## Current Focus
6
6
 
7
- `0.2.18` adds the first live persona automation lane:
7
+ `0.2.19` adds the first live persona automation lane:
8
8
  - WebSpatial-based persona scaffolding for generated Oomi apps
9
+ - a high-level `oomi personas create-managed` command for agent-driven persona creation
9
10
  - device-authenticated persona runtime registration and job callbacks
10
11
  - automatic bridge-side polling for queued `persona_job` control messages
11
12
  - end-to-end local persona startup from a structured orchestration payload
@@ -153,6 +154,7 @@ oomi personas scaffold market-analyst --name "Market Analyst" --description "Pri
153
154
 
154
155
  Use:
155
156
  - `oomi personas create <id>` for repo-local manifest work
157
+ - `oomi personas create-managed --name "Cooking Persona" --description "Private cooking workspace"` for the end-to-end Oomi-managed persona flow
156
158
  - `oomi personas scaffold <slug>` for a WebSpatial-based Oomi app shell with runtime metadata and health documents
157
159
  - `oomi persona-jobs execute --message-file <job.json>` when OpenClaw receives a structured persona orchestration job from Oomi
158
160
 
@@ -166,7 +168,13 @@ oomi persona-jobs succeed pj_123 --workspace-path ~/.openclaw/personas/market-an
166
168
  oomi persona-jobs fail pj_123 --code JOB_FAILED --message "Scaffold generation failed."
167
169
  ```
168
170
 
169
- When the managed bridge is running, `oomi-ai` now also polls the backend control lane for queued `persona_job` messages and executes them automatically. That poll path is filtered to `metadata.type = persona_job`, so it does not consume normal queued chat traffic.
171
+ Recommended agent flow:
172
+
173
+ ```bash
174
+ oomi personas create-managed --name "Cooking Persona" --description "Private cooking workspace for recipes, meal planning, and kitchen notes."
175
+ ```
176
+
177
+ That command creates the managed persona record in Oomi using the linked device identity. The backend then enqueues the `persona_job`, and the running bridge consumes that job automatically. The poll path is filtered to `metadata.type = persona_job`, so it does not consume normal queued chat traffic.
170
178
 
171
179
  ## Bridge Health States
172
180
 
@@ -194,6 +194,13 @@ Aliases allowed if needed:
194
194
 
195
195
  ## Persona App Generation
196
196
 
197
+ When a user asks you in chat to create a new persona for Oomi:
198
+
199
+ 1. Prefer `oomi personas create-managed --name "<name>" --description "<description>"`.
200
+ 2. That is the primary end-to-end command for agent-driven persona creation.
201
+ 3. It creates the managed persona record in Oomi and relies on the running bridge to consume the queued `persona_job` automatically.
202
+ 4. Do not manually scaffold first unless you are recovering a failed persona job or working outside the queued Oomi flow.
203
+
197
204
  When generating a managed persona app for Oomi:
198
205
 
199
206
  1. Do not build the app shell from scratch.
package/bin/oomi-ai.js CHANGED
@@ -190,6 +190,8 @@ Commands:
190
190
 
191
191
  personas create <id>
192
192
  Create a new persona manifest and optionally sync it to the backend.
193
+ personas create-managed [slug]
194
+ Create a managed persona in Oomi and enqueue its build job for the linked device.
193
195
  personas scaffold <slug>
194
196
  Create an Oomi-managed persona app scaffold for agent customization.
195
197
  personas runtime-register <slug>
@@ -225,9 +227,10 @@ Common flags:
225
227
  --json Print pairing result as JSON (for automation)
226
228
  --backend-url URL Override Oomi backend URL
227
229
  --root PATH Override repo root path for persona discovery
228
- --name NAME Persona display name (for create)
229
- --description TEXT Persona description (for scaffold)
230
- --summary TEXT Persona summary (for create)
230
+ --name NAME Persona display name (for create)
231
+ --description TEXT Persona description (for scaffold)
232
+ --slug SLUG Explicit slug override (for create-managed)
233
+ --summary TEXT Persona summary (for create)
231
234
  --status STATUS Persona status (for create)
232
235
  --type TYPE Persona type (for create)
233
236
  --tags a,b,c Persona tags (for create)
@@ -595,6 +598,32 @@ function printPersonaScaffoldResult(result, asJson = false) {
595
598
  }
596
599
  }
597
600
 
601
+ function printManagedPersonaCreateResult(result, asJson = false) {
602
+ if (asJson) {
603
+ console.log(JSON.stringify(result, null, 2));
604
+ return;
605
+ }
606
+
607
+ const persona = result?.persona && typeof result.persona === 'object' ? result.persona : {};
608
+ const personaJob = result?.personaJob && typeof result.personaJob === 'object' ? result.personaJob : {};
609
+ console.log(`Managed persona created: ${String(persona.name || persona.slug || 'unknown')}`);
610
+ if (persona.slug) {
611
+ console.log(`Slug: ${persona.slug}`);
612
+ }
613
+ if (persona.lifecycle) {
614
+ console.log(`Lifecycle: ${persona.lifecycle}`);
615
+ }
616
+ if (personaJob.jobId) {
617
+ console.log(`Persona job: ${personaJob.jobId}`);
618
+ }
619
+ if (personaJob.status) {
620
+ console.log(`Job status: ${personaJob.status}`);
621
+ }
622
+ if (personaJob.deviceId) {
623
+ console.log(`Assigned device: ${personaJob.deviceId}`);
624
+ }
625
+ }
626
+
598
627
  function parseOptionalPositiveInteger(value) {
599
628
  if (value === undefined || value === null || value === '') return null;
600
629
  const parsed = Number(value);
@@ -932,6 +961,26 @@ async function handlePersonaJobExecuteCommand(flags = {}) {
932
961
 
933
962
  printStructuredResult(result, isTruthyFlag(flags.json));
934
963
  }
964
+
965
+ async function handlePersonaCreateManagedCommand(flags = {}, positionalSlug = '') {
966
+ const name = String(flags.name || '').trim();
967
+ if (!name) {
968
+ throw new Error('Persona name is required. Usage: oomi personas create-managed [slug] --name "<name>" --description "<description>"');
969
+ }
970
+
971
+ const description = String(flags.description || '').trim() || name;
972
+ const explicitSlug = String(flags.slug || positionalSlug || '').trim();
973
+ const client = createCliPersonaApiClient(flags);
974
+ const result = await client.createManagedPersona({
975
+ slug: explicitSlug,
976
+ name,
977
+ description,
978
+ templateType: String(flags['template-type'] || 'persona-app').trim() || 'persona-app',
979
+ promptTemplateVersion: String(flags['template-version'] || 'v1').trim() || 'v1',
980
+ });
981
+
982
+ printManagedPersonaCreateResult(result, isTruthyFlag(flags.json));
983
+ }
935
984
 
936
985
  function resolveOpenclawConfigPath() {
937
986
  const candidates = [
@@ -3964,15 +4013,20 @@ async function main() {
3964
4013
  return;
3965
4014
  }
3966
4015
 
3967
- if (command === 'personas' && subcommand === 'create') {
4016
+ if (command === 'personas' && subcommand === 'create') {
3968
4017
  const id = args.positionals[0];
3969
4018
  if (!id) {
3970
4019
  throw new Error('Persona id is required. Usage: oomi personas create <id>');
3971
4020
  }
3972
4021
  await createPersona({ id, root: args.flags.root, flags: args.flags });
3973
4022
  return;
3974
- }
3975
-
4023
+ }
4024
+
4025
+ if (command === 'personas' && subcommand === 'create-managed') {
4026
+ await handlePersonaCreateManagedCommand(args.flags, args.positionals[0]);
4027
+ return;
4028
+ }
4029
+
3976
4030
  if (command === 'personas' && subcommand === 'scaffold') {
3977
4031
  const slug = args.positionals[0];
3978
4032
  if (!slug) {
@@ -66,6 +66,38 @@ export function createPersonaApiClient({
66
66
  }
67
67
 
68
68
  return {
69
+ createManagedPersona({
70
+ slug,
71
+ name,
72
+ description,
73
+ templateType = 'persona-app',
74
+ promptTemplateVersion = 'v1',
75
+ }) {
76
+ const safeName = trimString(name);
77
+ if (!safeName) {
78
+ throw new Error('Persona name is required.');
79
+ }
80
+
81
+ const body = withDevice({
82
+ name: safeName,
83
+ description: trimString(description) || safeName,
84
+ templateType: trimString(templateType) || 'persona-app',
85
+ promptTemplateVersion: trimString(promptTemplateVersion) || 'v1',
86
+ });
87
+ const safeSlug = trimString(slug);
88
+ if (safeSlug) {
89
+ body.slug = safeSlug;
90
+ }
91
+
92
+ return postJson({
93
+ fetchImpl,
94
+ backendUrl: resolvedBackendUrl,
95
+ deviceToken: resolvedDeviceToken,
96
+ path: '/v1/personas/managed_create',
97
+ body,
98
+ });
99
+ },
100
+
69
101
  registerRuntime({
70
102
  slug,
71
103
  endpoint,
@@ -2,7 +2,7 @@
2
2
  "id": "oomi-ai",
3
3
  "name": "Oomi Channel Plugin",
4
4
  "description": "Managed Oomi channel integration for OpenClaw.",
5
- "version": "0.2.18",
5
+ "version": "0.2.19",
6
6
  "author": "Oomi",
7
7
  "license": "MIT",
8
8
  "openclawVersion": ">=0.5.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oomi-ai",
3
- "version": "0.2.18",
3
+ "version": "0.2.19",
4
4
  "description": "Oomi OpenClaw channel plugin and bridge tooling",
5
5
  "bin": {
6
6
  "oomi": "bin/oomi-ai.js"