Skip to content
Merged
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
28 changes: 14 additions & 14 deletions assets/dist/roundtable.js

Large diffs are not rendered by default.

24 changes: 20 additions & 4 deletions assets/src/components.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,23 @@ const STREAM_FIRST_EVENT_TIMEOUT_MS = 15000;
* @param {string} text
* @param {{setTurns:Function, setBusy:Function, streamFn?:Function, sendFn?:Function, timeoutMs?:number, trigger?:string, onSignal?:(ev:object)=>void}} opts
*/
/**
* Human-readable message for a failed turn, keyed by the error kind when known.
* @param {string|undefined} kind
* @returns {string}
*/
function errorText(kind) {
if (kind === 'licence_invalid' || kind === 'http_402') {
return 'Your product licence could not be verified. Check your licence in the plugin settings, then try again.';
}
if (kind === 'over_quota' || kind === 'http_429') {
return "You've reached the usage limit for now. Please try again in a little while.";
}
return 'Something went wrong. Please try again.';
}

export async function sendTurn(text, {

setTurns, setBusy, streamFn = streamMessage, sendFn = sendMessage, timeoutMs = STREAM_FIRST_EVENT_TIMEOUT_MS,
trigger, onSignal,
}) {
Expand All @@ -48,7 +64,7 @@ export async function sendTurn(text, {
setTurns((t) => {
const next = t.slice();
const i = next.length - 1;
next[i] = { ...next[i], error: true, done: true };
next[i] = { ...next[i], error: true, errorKind: res.error.kind, done: true };
return next;
});
return;
Expand Down Expand Up @@ -151,7 +167,7 @@ export function applyStreamEvent(turns, ev, now) {
patch = (turn.reply === '' && turn.finalText)
? { ...base, reply: turn.finalText }
: base;
} else if (ev.type === 'error') patch = { error: true };
} else if (ev.type === 'error') patch = { error: true, errorKind: ev.message };
else return turns;
const next = turns.slice();
next[i] = { ...turn, ...patch };
Expand Down Expand Up @@ -282,7 +298,7 @@ function TypedBubble({ turn, streaming }) {
return (
<div class={'rt-ab' + (turn.error ? ' rt-ab-error' : '')}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: turn.error ? 'Something went wrong. Please try again.' : renderMarkdown(text) }} />
dangerouslySetInnerHTML={{ __html: turn.error ? errorText(turn.errorKind) : renderMarkdown(text) }} />
);
}

Expand Down Expand Up @@ -320,7 +336,7 @@ function Bubble({ turn, onChipSend, chipDisabled }) {
)}
{turn.done && vsteps.length > 0 && (
<details class="rt-activity">
<summary>Code doorzocht · {vsteps.length} {vsteps.length === 1 ? 'stap' : 'stappen'}</summary>
<summary>Searched the code · {vsteps.length} {vsteps.length === 1 ? 'step' : 'steps'}</summary>
<ul>
{vsteps.map((s, i) => {
const nextAt = i + 1 < vsteps.length ? vsteps[i + 1].at : turn.doneAt;
Expand Down
1 change: 1 addition & 0 deletions src/HubClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ private function guardStatus( int $status ): void {
return;
}
throw match ( $status ) {
402 => \EpicWP\Roundtable\HubException::licenceInvalid(),
403 => \EpicWP\Roundtable\HubException::blocked(),
429 => \EpicWP\Roundtable\HubException::overQuota(),
default => \EpicWP\Roundtable\HubException::server( $status ),
Expand Down
7 changes: 7 additions & 0 deletions src/HubException.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ final class HubException extends \RuntimeException {
public const BLOCKED = 'blocked';
/** The subject is over its request quota (HTTP 429). */
public const OVER_QUOTA = 'over_quota';

public const LICENCE_INVALID = 'licence_invalid';
/** A transport-level failure (no HTTP response). */
public const NETWORK = 'network';
/** The hub returned a server error. */
Expand All @@ -32,6 +34,11 @@ public static function overQuota(): self {
return new self( self::OVER_QUOTA, 'The request was refused (over quota).' );
}

/** The install's licence failed hub-side verification (HTTP 402). */
public static function licenceInvalid(): self {
return new self( self::LICENCE_INVALID, 'The request was refused (licence invalid).' );
}

/**
* A transport-level failure (no HTTP response). `$detail` must not contain secrets.
*
Expand Down
1 change: 1 addition & 0 deletions src/MessageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ private function serialize( TurnResult $result ): array {
*/
private function statusFor( \EpicWP\Roundtable\HubException $error ): int {
return match ( $error->kind() ) {
\EpicWP\Roundtable\HubException::LICENCE_INVALID => 402,
\EpicWP\Roundtable\HubException::BLOCKED => 403,
\EpicWP\Roundtable\HubException::OVER_QUOTA => 429,
default => 502,
Expand Down
1 change: 1 addition & 0 deletions tests/HubClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public function test_uses_the_hub_base_url_override_when_set(): void
public static function errorStatuses(): array
{
return [
'licence' => [402, HubException::LICENCE_INVALID],
'blocked' => [403, HubException::BLOCKED],
'over quota' => [429, HubException::OVER_QUOTA],
'server' => [503, HubException::SERVER],
Expand Down
Loading