PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.10
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.10
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
← All changes | includes/agents/rest.php +115 -5 1.1.11.1.10 View file →
@@ -73,8 +73,35 @@
73 73 'type' => 'array',
74 74 'default' => array(),
75 75 'items' => array( 'type' => 'string' ),
76 76 ),
77 + // Like `face`, deliberately schema-light. Each row
78 + // is validated against the live trigger-kind
79 + // catalogue by openstation_agent_sanitize_triggers(),
80 + // which drops rows it does not recognise rather
81 + // than rejecting the whole create.
82 + 'triggers' => array(
83 + 'type' => 'array',
84 + 'default' => array(),
85 + ),
86 + 'vibes' => array(
87 + 'type' => 'string',
88 + 'default' => '',
89 + ),
90 + // `face` carries no schema beyond "object" and no
91 + // sanitize_callback on purpose. The real validator is
92 + // openstation_agent_sanitize_face_json(), which clamps
93 + // every number; a partial JSON Schema here would only
94 + // suggest the route had checked it.
95 + 'face' => array(
96 + 'type' => 'object',
97 + 'default' => null,
98 + ),
99 + 'faceSeed' => array(
100 + 'type' => 'integer',
101 + 'default' => 0,
102 + 'sanitize_callback' => 'absint',
103 + ),
77 104 ),
78 105 ),
79 106 )
80 107 );
@@ -90,8 +117,26 @@
90 117 );
91 118
92 119 register_rest_route(
93 120 $namespace,
121 + '/agents/draft',
122 + array(
123 + 'methods' => WP_REST_Server::CREATABLE,
124 + 'permission_callback' => 'openstation_agents_rest_write_permission',
125 + 'callback' => 'openstation_agents_rest_draft',
126 + 'args' => array(
127 + 'brief' => array(
128 + 'type' => 'string',
129 + 'required' => true,
130 + 'sanitize_callback' => 'sanitize_textarea_field',
131 + 'validate_callback' => 'openstation_agents_rest_validate_brief',
132 + ),
133 + ),
134 + )
135 + );
136 +
137 + register_rest_route(
138 + $namespace,
94 139 '/agents/trigger-kinds',
95 140 array(
96 141 'methods' => WP_REST_Server::READABLE,
97 142 'permission_callback' => 'openstation_agents_rest_read_permission',
@@ -148,14 +193,22 @@
148 193 'methods' => WP_REST_Server::CREATABLE,
149 194 'permission_callback' => 'openstation_agents_rest_invoke_permission',
150 195 'callback' => 'openstation_agents_rest_invoke',
151 196 'args' => array(
152 - 'message' => array(
197 + 'async' => array(
198 + 'type' => 'boolean',
199 + 'default' => false,
200 + ),
201 + 'requestId' => array(
202 + 'type' => 'string',
203 + 'format' => 'uuid',
204 + ),
205 + 'message' => array(
153 206 'type' => 'string',
154 207 'required' => true,
155 208 'sanitize_callback' => 'sanitize_textarea_field',
156 209 ),
157 - 'source' => array(
210 + 'source' => array(
158 211 'type' => 'string',
159 212 'default' => 'chat',
160 213 'enum' => array( 'chat', 'drag', 'send-to' ),
161 214 'sanitize_callback' => 'sanitize_key',
@@ -163,9 +216,9 @@
163 216 // Prior conversation turns, oldest first. Without these
164 217 // every message is a contextless run — a follow-up like
165 218 // "yes, do it" would be resolved against nothing and the
166 219 // agent could act on the wrong entity entirely.
167 - 'history' => array(
220 + 'history' => array(
168 221 'type' => 'array',
169 222 'default' => array(),
170 223 'items' => array(
171 224 'type' => 'object',
@@ -290,8 +343,13 @@
290 343 * @param WP_REST_Request $request REST request.
291 344 * @return WP_REST_Response|WP_Error
292 345 */
293 346 function openstation_agents_rest_create( WP_REST_Request $request ) {
347 + // Every field the route declares is forwarded. `vibes`, `face` and
348 + // `faceSeed` are the character half of an agent, and a create that
349 + // took the name and dropped the portrait is how an agent ends up
350 + // wearing the fallback glyph seconds after someone picked a face
351 + // for it. `openstation_agent_create()` sanitizes each one.
294 352 $user = openstation_agent_create(
295 353 array(
296 354 'name' => (string) $request['name'],
297 355 'role' => (string) $request['role'],
@@ -297,8 +355,12 @@
297 355 'role' => (string) $request['role'],
298 356 'description' => (string) $request['description'],
299 357 'instructions' => (string) $request['instructions'],
300 358 'abilities' => (array) $request['abilities'],
359 + 'triggers' => (array) $request['triggers'],
360 + 'vibes' => (string) $request['vibes'],
361 + 'face' => $request['face'],
362 + 'faceSeed' => (int) $request['faceSeed'],
301 363 )
302 364 );
303 365 if ( is_wp_error( $user ) ) {
304 366 $data = $user->get_error_data();
@@ -337,9 +399,21 @@
337 399 $body = array();
338 400 }
339 401
340 402 $fields = array();
341 - $allowed = array( 'name', 'role', 'description', 'instructions', 'abilities', 'triggers', 'model', 'rateLimit' );
403 + $allowed = array(
404 + 'name',
405 + 'role',
406 + 'description',
407 + 'instructions',
408 + 'abilities',
409 + 'triggers',
410 + 'model',
411 + 'rateLimit',
412 + 'vibes',
413 + 'face',
414 + 'faceSeed',
415 + );
342 416 foreach ( $allowed as $field ) {
343 417 if ( array_key_exists( $field, $body ) ) {
344 418 $fields[ $field ] = $body[ $field ];
345 419 }
@@ -415,8 +489,12 @@
415 489 array( 'status' => rest_authorization_required_code() )
416 490 );
417 491 }
418 492
493 + if ( $request['async'] ) {
494 + return openstation_agents_rest_enqueue_job( $request );
495 + }
496 +
419 497 $result = openstation_agent_invoke(
420 498 (int) $user->ID,
421 499 (string) $request['message'],
422 500 array(
@@ -444,8 +522,37 @@
444 522 return rest_ensure_response( openstation_agents_abilities_catalogue() );
445 523 }
446 524
447 525 /**
526 + * `brief` must carry words and fit the drafting cap.
527 + *
528 + * @param mixed $value Raw param.
529 + * @return bool
530 + */
531 +function openstation_agents_rest_validate_brief( $value ) {
532 + return is_string( $value )
533 + && '' !== trim( $value )
534 + && mb_strlen( $value ) <= OPENSTATION_AGENT_DRAFT_BRIEF_MAX;
535 +}
536 +
537 +/**
538 + * POST /agents/draft — draft a definition from a brief.
539 + *
540 + * Nothing is created: the wizard shows the draft for review and the
541 + * create route is still the only way an agent comes to exist.
542 + *
543 + * @param WP_REST_Request $request Request.
544 + * @return WP_REST_Response|WP_Error
545 + */
546 +function openstation_agents_rest_draft( WP_REST_Request $request ) {
547 + $draft = openstation_agent_draft( (string) $request['brief'], get_current_user_id() );
548 + if ( is_wp_error( $draft ) ) {
549 + return $draft;
550 + }
551 + return rest_ensure_response( $draft );
552 +}
553 +
554 +/**
448 555 * GET /agents/trigger-kinds — the trigger-kinds catalogue.
449 556 *
450 557 * @return WP_REST_Response
451 558 */
@@ -501,9 +608,9 @@
501 608 }
502 609
503 610 $avatar = get_avatar_url( $user->ID, array( 'size' => 96 ) );
504 611 if ( ! is_string( $avatar ) || '' === $avatar ) {
505 - $avatar = openstation_agent_avatar_url();
612 + $avatar = openstation_agent_avatar_url( (int) $user->ID );
506 613 }
507 614
508 615 return array(
509 616 'id' => (int) $user->ID,
@@ -515,7 +622,10 @@
515 622 'abilities' => openstation_agent_get_abilities( (int) $user->ID ),
516 623 'triggers' => openstation_agent_get_triggers( (int) $user->ID ),
517 624 'model' => openstation_agent_get_model( (int) $user->ID ),
518 625 'rateLimit' => openstation_agent_get_rate_limit( (int) $user->ID ),
626 + 'vibes' => openstation_agent_get_vibes( (int) $user->ID ),
627 + 'face' => openstation_agent_get_face( (int) $user->ID ),
628 + 'faceSeed' => openstation_agent_get_face_seed( (int) $user->ID ),
519 629 'avatarUrl' => $avatar,
520 630 );
521 631 }