@theoremjs/react 0.3.4-next.363.g11be542 → 0.3.4-next.375.ga2d1878
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 +23 -336
- package/client/host-call.d.ts +2 -2
- package/client/host-call.js +1 -2
- package/client/index.d.ts +1 -28
- package/client/index.js +1 -22
- package/client/live/apply-live-turn-tool-event.js +1 -1
- package/client/live/run-live-tool-call.d.ts +1 -3
- package/client/live/run-live-tool-call.js +1 -1
- package/client/transcript-groups.js +1 -1
- package/client/voice-recorder.js +1 -1
- package/components/live/use-live-runner-controls.d.ts +1 -2
- package/components/live/use-live-runner-model.d.ts +7 -8
- package/components/live/use-live-runner-model.js +1 -2
- package/components/live/use-live-runner-ui.d.ts +2 -4
- package/components/live/use-live-runner-ui.js +1 -1
- package/components/live/use-live-session-client.d.ts +2 -5
- package/components/live/use-live-session-client.js +1 -1
- package/hooks/use-described.d.ts +1 -1
- package/hooks/use-described.js +1 -1
- package/hooks/use-embedding-index.d.ts +1 -1
- package/hooks/use-embedding-index.js +1 -1
- package/hooks/use-one-call.d.ts +2 -2
- package/hooks/use-one-call.js +1 -2
- package/hooks/use-page-tool-warnings.d.ts +2 -5
- package/hooks/use-page-tool-warnings.js +3 -14
- package/hooks/use-theorem-chat.d.ts +35 -81
- package/hooks/use-theorem-chat.js +30 -522
- package/hooks/use-theorem-decision.d.ts +1 -2
- package/hooks/use-theorem-embedding.d.ts +1 -2
- package/hooks/use-theorem-host.d.ts +2 -4
- package/hooks/use-theorem-host.js +1 -4
- package/hooks/use-theorem-interface.d.ts +1 -2
- package/hooks/use-trace-records.d.ts +1 -1
- package/index.d.ts +2 -3
- package/index.js +2 -3
- package/live.d.ts +1 -2
- package/package.json +3 -2
- package/server/mod.d.ts +1 -26
- package/server/mod.js +1 -24
- package/ui/ChatComposerBar.d.ts +1 -1
- package/ui/ChatComposerBar.js +1 -3
- package/ui/ChatTranscript.d.ts +1 -1
- package/ui/ChatTranscript.js +1 -1
- package/ui/ConsoleFrame.d.ts +1 -1
- package/ui/DecisionAnswers.d.ts +1 -1
- package/ui/EmbeddingDocuments.d.ts +2 -2
- package/ui/EmbeddingDocuments.js +1 -2
- package/ui/EmbeddingQuery.d.ts +1 -1
- package/ui/EmbeddingQuery.js +1 -2
- package/ui/EmbeddingResults.d.ts +1 -1
- package/ui/EmbeddingResults.js +1 -1
- package/ui/EmbeddingSpace.d.ts +1 -2
- package/ui/LiveRunner.d.ts +1 -2
- package/ui/SchemaFields.d.ts +1 -1
- package/ui/SchemaFields.js +1 -2
- package/ui/ShapedData.js +1 -1
- package/ui/StateFields.js +1 -1
- package/ui/TheoremChat.d.ts +2 -2
- package/ui/TheoremChat.js +1 -1
- package/ui/TheoremDecision.d.ts +1 -1
- package/ui/TheoremDecision.js +1 -1
- package/ui/TheoremEmbedding.d.ts +1 -1
- package/ui/TheoremEmbedding.js +1 -2
- package/ui/TheoremHost.d.ts +2 -3
- package/ui/TheoremHost.js +1 -3
- package/ui/ToolGateCard.d.ts +1 -1
- package/ui/ToolGateCard.js +1 -2
- package/ui/ToolResult.d.ts +1 -1
- package/ui/ToolResult.js +1 -2
- package/ui/ToolResultCharts.d.ts +1 -1
- package/ui/ToolResultCharts.js +1 -2
- package/ui/TraceInspector.d.ts +1 -1
- package/ui/TraceInspectorPanel.d.ts +1 -1
- package/ui/approval-heading.js +1 -1
- package/ui/embedding-space-gl.d.ts +2 -2
- package/ui/embedding-space-gl.js +1 -1
- package/ui/index.d.ts +1 -1
- package/ui/labels.d.ts +1 -2
- package/client/audio-level.d.ts +0 -5
- package/client/audio-level.js +0 -24
- package/client/composer-drawer.d.ts +0 -19
- package/client/composer-drawer.js +0 -15
- package/client/composer-hints.d.ts +0 -25
- package/client/composer-hints.js +0 -20
- package/client/composer-primary.d.ts +0 -16
- package/client/composer-primary.js +0 -25
- package/client/decision-transport.d.ts +0 -70
- package/client/decision-transport.js +0 -175
- package/client/decode-composer-draft.d.ts +0 -11
- package/client/decode-composer-draft.js +0 -12
- package/client/embedding-input.d.ts +0 -84
- package/client/embedding-input.js +0 -194
- package/client/embedding-space.d.ts +0 -82
- package/client/embedding-space.js +0 -389
- package/client/embedding-transport.d.ts +0 -40
- package/client/embedding-transport.js +0 -71
- package/client/encode-composer-draft.d.ts +0 -9
- package/client/encode-composer-draft.js +0 -34
- package/client/encode-files.d.ts +0 -18
- package/client/encode-files.js +0 -54
- package/client/failure.d.ts +0 -29
- package/client/failure.js +0 -34
- package/client/generation-selection.d.ts +0 -15
- package/client/generation-selection.js +0 -24
- package/client/host-transport.d.ts +0 -70
- package/client/host-transport.js +0 -75
- package/client/live/live-mic-forward.d.ts +0 -30
- package/client/live/live-mic-forward.js +0 -46
- package/client/live/live-page-tool.d.ts +0 -34
- package/client/live/live-page-tool.js +0 -11
- package/client/live/live-state.d.ts +0 -13
- package/client/live/live-state.js +0 -22
- package/client/live/live-tool.d.ts +0 -11
- package/client/live/live-tool.js +0 -1
- package/client/live-client.d.ts +0 -189
- package/client/live-client.js +0 -829
- package/client/live-errors.d.ts +0 -2
- package/client/live-errors.js +0 -9
- package/client/live-messages.d.ts +0 -148
- package/client/live-messages.js +0 -100
- package/client/mic-capture.d.ts +0 -4
- package/client/mic-capture.js +0 -6
- package/client/oauth-popup.d.ts +0 -26
- package/client/oauth-popup.js +0 -30
- package/client/page-dispatch.d.ts +0 -15
- package/client/page-dispatch.js +0 -63
- package/client/pcm-downsample.d.ts +0 -4
- package/client/pcm-downsample.js +0 -45
- package/client/run-commit.d.ts +0 -34
- package/client/run-commit.js +0 -49
- package/client/run-session.d.ts +0 -79
- package/client/run-session.js +0 -207
- package/client/schema-fields.d.ts +0 -63
- package/client/schema-fields.js +0 -199
- package/client/shaped-data.d.ts +0 -118
- package/client/shaped-data.js +0 -343
- package/client/source-citations.d.ts +0 -13
- package/client/source-citations.js +0 -56
- package/client/space-geometry.d.ts +0 -39
- package/client/space-geometry.js +0 -183
- package/client/tool-result.d.ts +0 -78
- package/client/tool-result.js +0 -293
- package/client/tool-resume.d.ts +0 -50
- package/client/tool-resume.js +0 -14
- package/client/trace-feed.d.ts +0 -13
- package/client/trace-feed.js +0 -18
- package/client/transcript-schema.d.ts +0 -10
- package/client/transcript-schema.js +0 -120
- package/client/transport.d.ts +0 -264
- package/client/transport.js +0 -330
- package/client/turn-client.d.ts +0 -44
- package/client/turn-client.js +0 -88
- package/client/wire-line.d.ts +0 -56
- package/client/wire-line.js +0 -90
- package/client/worklets/mic-capture.js +0 -16
- package/hooks/use-theorem-chat-actions.d.ts +0 -79
- package/hooks/use-theorem-chat-actions.js +0 -287
- package/hooks/use-theorem-chat-state.d.ts +0 -66
- package/hooks/use-theorem-chat-state.js +0 -122
- package/server/checkpoint-ownership.d.ts +0 -6
- package/server/checkpoint-ownership.js +0 -42
- package/server/conversation-store.d.ts +0 -92
- package/server/conversation-store.js +0 -131
- package/server/conversation.d.ts +0 -193
- package/server/conversation.js +0 -552
- package/server/credential-store.d.ts +0 -24
- package/server/credential-store.js +0 -14
- package/server/decision-handler.d.ts +0 -42
- package/server/decision-handler.js +0 -46
- package/server/embedding-handler.d.ts +0 -33
- package/server/embedding-handler.js +0 -45
- package/server/handler.d.ts +0 -158
- package/server/handler.js +0 -775
- package/server/json-response.d.ts +0 -2
- package/server/json-response.js +0 -7
- package/server/mcp-handler.d.ts +0 -46
- package/server/mcp-handler.js +0 -312
- package/server/page-dispatch.d.ts +0 -22
- package/server/page-dispatch.js +0 -127
- package/server/request-body.d.ts +0 -2
- package/server/request-body.js +0 -42
- package/server/request-check.d.ts +0 -21
- package/server/request-check.js +0 -49
- package/server/session-authority.d.ts +0 -8
- package/server/session-authority.js +0 -78
- package/server/session-boundary.d.ts +0 -26
- package/server/session-boundary.js +0 -64
- package/server/session-identity.d.ts +0 -16
- package/server/session-identity.js +0 -41
- package/server/session-limits.d.ts +0 -12
- package/server/session-limits.js +0 -59
- package/server/session-store.d.ts +0 -123
- package/server/session-store.js +0 -264
- package/server/single-action.d.ts +0 -21
- package/server/single-action.js +0 -30
- package/server/steer-inbox.d.ts +0 -35
- package/server/steer-inbox.js +0 -52
- package/server/tool-operations.d.ts +0 -6
- package/server/tool-operations.js +0 -132
- package/server/turn-input.d.ts +0 -10
- package/server/turn-input.js +0 -29
package/client/turn-client.js
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { labelText, TheoremError } from '@theoremjs/agents';
|
|
2
|
-
import { foldTurnEvents, prepareUserTurn, streamThoughtsEnabled, } from '@theoremjs/agents/interface';
|
|
3
|
-
import { filesToPending } from "./encode-files.js";
|
|
4
|
-
import { defaultModel } from "./generation-selection.js";
|
|
5
|
-
export function issuedOperationId(call) {
|
|
6
|
-
if (!call.operationId)
|
|
7
|
-
throw new TheoremError('request', labelText('session.gate_expired'));
|
|
8
|
-
return call.operationId;
|
|
9
|
-
}
|
|
10
|
-
function resolveModelId(iface, session) {
|
|
11
|
-
return session.selectedModel ?? defaultModel(iface);
|
|
12
|
-
}
|
|
13
|
-
function resolveEffort(iface, session, modelId) {
|
|
14
|
-
if (!modelId || !Object.hasOwn(iface.models, modelId))
|
|
15
|
-
return undefined;
|
|
16
|
-
const binding = iface.models[modelId];
|
|
17
|
-
if (!binding.allowEffortSelect)
|
|
18
|
-
return undefined;
|
|
19
|
-
return session.selectedEffort ?? binding.defaultEffort;
|
|
20
|
-
}
|
|
21
|
-
/** Model / effort selection the host should honour for this session. */
|
|
22
|
-
function generationFields(iface, session) {
|
|
23
|
-
const modelId = resolveModelId(iface, session);
|
|
24
|
-
const model = iface.allowModelSelect ? modelId : undefined;
|
|
25
|
-
const effort = resolveEffort(iface, session, modelId);
|
|
26
|
-
return { ...(model ? { model } : {}), ...(effort ? { effort } : {}) };
|
|
27
|
-
}
|
|
28
|
-
function gateReplay(iface, session, call) {
|
|
29
|
-
return {
|
|
30
|
-
name: call.name,
|
|
31
|
-
input: call.input,
|
|
32
|
-
...(call.gateKind ? { gateKind: call.gateKind } : {}),
|
|
33
|
-
sessionPermissions: call.sessionPermissions ?? session.sessionPermissions,
|
|
34
|
-
...(session.toolSnapshot ? { snapshot: session.toolSnapshot } : {}),
|
|
35
|
-
...(session.promotedToolIds.length ? { promoted: [...session.promotedToolIds] } : {}),
|
|
36
|
-
...generationFields(iface, session),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
function scopeFields(scope) {
|
|
40
|
-
return {
|
|
41
|
-
...(scope.conversation ? { conversation: scope.conversation } : {}),
|
|
42
|
-
...(scope.turnId ? { turnId: scope.turnId } : {}),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
export function buildTurnRequest(iface, session, input, options = {}) {
|
|
46
|
-
const abandon = (options.walkAway?.calls ?? []).map((call) => ({
|
|
47
|
-
callId: call.callId,
|
|
48
|
-
operationId: issuedOperationId(call),
|
|
49
|
-
}));
|
|
50
|
-
return {
|
|
51
|
-
...scopeFields(options),
|
|
52
|
-
...generationFields(iface, session),
|
|
53
|
-
input,
|
|
54
|
-
...(abandon.length ? { abandon } : {}),
|
|
55
|
-
replay: { sessionPermissions: session.sessionPermissions },
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
export function buildInvokeRequest(iface, session, args, scope = {}) {
|
|
59
|
-
return {
|
|
60
|
-
...scopeFields(scope),
|
|
61
|
-
gateId: args.gateId,
|
|
62
|
-
operationId: args.operationId,
|
|
63
|
-
decision: args.decision,
|
|
64
|
-
...(args.secret === undefined ? {} : { secret: args.secret }),
|
|
65
|
-
...(args.page === undefined ? {} : { page: args.page }),
|
|
66
|
-
replay: gateReplay(iface, session, {
|
|
67
|
-
...args,
|
|
68
|
-
gateKind: args.gateKind ??
|
|
69
|
-
(session.gatedTool?.callId === args.gateId ? session.gatedTool.gateKind : undefined),
|
|
70
|
-
}),
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
export function projectUserTurn(iface, draft) {
|
|
74
|
-
return prepareUserTurn(iface.inputs, draft, iface.guardrails);
|
|
75
|
-
}
|
|
76
|
-
export function prepareComposerTurn(iface, text, pendingFiles, pendingVoice = []) {
|
|
77
|
-
return projectUserTurn(iface, {
|
|
78
|
-
...(text.trim() ? { text } : {}),
|
|
79
|
-
...(pendingFiles.length ? { attachments: filesToPending(pendingFiles) } : {}),
|
|
80
|
-
...(pendingVoice.length ? { voice: filesToPending(pendingVoice) } : {}),
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
export function foldAssistantTurn(iface, events) {
|
|
84
|
-
// why: Its `turn-done` blocks stay: hidden in the view, they carry the reply's worked time.
|
|
85
|
-
return foldTurnEvents(events, {
|
|
86
|
-
showThoughts: streamThoughtsEnabled(iface.outputs),
|
|
87
|
-
});
|
|
88
|
-
}
|
package/client/wire-line.d.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Every value that reaches the browser over a wire (NDJSON lines, live
|
|
3
|
-
* envelopes) is checked against its schema here. A line or event of a kind the
|
|
4
|
-
* client does not know is reported as `unsupported`, and one that fails its
|
|
5
|
-
* check (not JSON, no kind, or a known kind that fails its schema) as
|
|
6
|
-
* `malformed`; either way the reply goes on. A whole reply that fails its check
|
|
7
|
-
* (the profile description) is `bad_response`.
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
import { TheoremError, z } from '@theoremjs/agents';
|
|
12
|
-
/**
|
|
13
|
-
* A line or envelope of a kind the client does not know. The server never
|
|
14
|
-
* sends it; the client's parser makes it so the host sees what arrived. Theorem
|
|
15
|
-
* shows nothing for it.
|
|
16
|
-
*/
|
|
17
|
-
export type UnsupportedEvent = {
|
|
18
|
-
type: 'unsupported';
|
|
19
|
-
received: string;
|
|
20
|
-
raw: unknown;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* A line or event that failed its wire check. The server never sends it; the
|
|
24
|
-
* client's reader makes it, leaves the line out, and the reply goes on. `error`
|
|
25
|
-
* is `bad_response`: its message names what broke, never the value, and the
|
|
26
|
-
* user reads `session.part_skipped`.
|
|
27
|
-
*/
|
|
28
|
-
export type MalformedEvent = {
|
|
29
|
-
type: 'malformed';
|
|
30
|
-
error: TheoremError;
|
|
31
|
-
};
|
|
32
|
-
/** Every kind a wire carries, and the schema a value of that kind must pass. */
|
|
33
|
-
export type WireLines<Line extends {
|
|
34
|
-
type: string;
|
|
35
|
-
}> = {
|
|
36
|
-
readonly [K in Line['type']]: z.ZodType<Extract<Line, {
|
|
37
|
-
type: K;
|
|
38
|
-
}>>;
|
|
39
|
-
};
|
|
40
|
-
/**
|
|
41
|
-
* Issue paths and codes only: a failure names what broke, never the value. A
|
|
42
|
-
* union that matched no branch lists each branch's issues.
|
|
43
|
-
*/
|
|
44
|
-
export declare function issueSummary(error: z.ZodError): string;
|
|
45
|
-
/** `raw` as `schema` reads it; one that fails is `bad_response`, naming `what`. */
|
|
46
|
-
export declare function checkWire<T>(schema: z.ZodType<T>, raw: unknown, what: string): T;
|
|
47
|
-
/** One wire value: a known kind that passed its schema, `unsupported`, or `malformed`. */
|
|
48
|
-
export declare function readWireValue<Line extends {
|
|
49
|
-
type: string;
|
|
50
|
-
}>(lines: WireLines<Line>, raw: unknown): Line | UnsupportedEvent | MalformedEvent;
|
|
51
|
-
/** One wire line's text: {@link readWireValue} of its JSON, or `malformed` when it is not JSON. */
|
|
52
|
-
export declare function readWireLine<Line extends {
|
|
53
|
-
type: string;
|
|
54
|
-
}>(lines: WireLines<Line>, text: string): Line | UnsupportedEvent | MalformedEvent;
|
|
55
|
-
/** A whole reply's JSON text as a value; text that is not JSON is `bad_response`. */
|
|
56
|
-
export declare function parseWireJson(text: string): unknown;
|
package/client/wire-line.js
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Every value that reaches the browser over a wire (NDJSON lines, live
|
|
3
|
-
* envelopes) is checked against its schema here. A line or event of a kind the
|
|
4
|
-
* client does not know is reported as `unsupported`, and one that fails its
|
|
5
|
-
* check (not JSON, no kind, or a known kind that fails its schema) as
|
|
6
|
-
* `malformed`; either way the reply goes on. A whole reply that fails its check
|
|
7
|
-
* (the profile description) is `bad_response`.
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
import { TheoremError, z } from '@theoremjs/agents';
|
|
12
|
-
const wireKind = z.object({ type: z.string() });
|
|
13
|
-
function isKnown(lines, type) {
|
|
14
|
-
return Object.hasOwn(lines, type);
|
|
15
|
-
}
|
|
16
|
-
function issuesSummary(issues, at) {
|
|
17
|
-
return issues
|
|
18
|
-
.map((issue) => {
|
|
19
|
-
const path = [...at, ...issue.path];
|
|
20
|
-
const head = `${path.map(String).join('.') || '(root)'} ${issue.code}`;
|
|
21
|
-
if (issue.code !== 'invalid_union' || issue.errors.length === 0)
|
|
22
|
-
return head;
|
|
23
|
-
return `${head} [${issue.errors.map((branch) => issuesSummary(branch, path)).join(' | ')}]`;
|
|
24
|
-
})
|
|
25
|
-
.join('; ');
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Issue paths and codes only: a failure names what broke, never the value. A
|
|
29
|
-
* union that matched no branch lists each branch's issues.
|
|
30
|
-
*/
|
|
31
|
-
export function issueSummary(error) {
|
|
32
|
-
return issuesSummary(error.issues, []);
|
|
33
|
-
}
|
|
34
|
-
function badResponse(what, error) {
|
|
35
|
-
// labels-exempt: internal diagnostic; the user reads error.bad_response
|
|
36
|
-
return new TheoremError('bad_response', `${what} failed its wire check: ${issueSummary(error)}`);
|
|
37
|
-
}
|
|
38
|
-
/** `raw` as `schema` reads it; one that fails is `bad_response`, naming `what`. */
|
|
39
|
-
export function checkWire(schema, raw, what) {
|
|
40
|
-
const parsed = schema.safeParse(raw);
|
|
41
|
-
if (!parsed.success)
|
|
42
|
-
throw badResponse(what, parsed.error);
|
|
43
|
-
return parsed.data;
|
|
44
|
-
}
|
|
45
|
-
function malformed(message) {
|
|
46
|
-
return {
|
|
47
|
-
type: 'malformed',
|
|
48
|
-
error: new TheoremError('bad_response', message, { copy: { key: 'session.part_skipped' } }),
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/** One wire value: a known kind that passed its schema, `unsupported`, or `malformed`. */
|
|
52
|
-
export function readWireValue(lines, raw) {
|
|
53
|
-
const kind = wireKind.safeParse(raw);
|
|
54
|
-
// labels-exempt: internal diagnostic; the user reads session.part_skipped
|
|
55
|
-
if (!kind.success)
|
|
56
|
-
return malformed(`a line without a kind failed its wire check: ${issueSummary(kind.error)}`);
|
|
57
|
-
const { type } = kind.data;
|
|
58
|
-
if (!isKnown(lines, type))
|
|
59
|
-
return { type: 'unsupported', received: type, raw };
|
|
60
|
-
const line = lines[type].safeParse(raw);
|
|
61
|
-
if (line.success)
|
|
62
|
-
return line.data;
|
|
63
|
-
// labels-exempt: internal diagnostic; the user reads session.part_skipped
|
|
64
|
-
return malformed(`a '${type}' line failed its wire check: ${issueSummary(line.error)}`);
|
|
65
|
-
}
|
|
66
|
-
/** JSON text as a value, or undefined when it is not JSON. The parser's own error quotes the text, so it is not kept. */
|
|
67
|
-
function jsonValue(text) {
|
|
68
|
-
try {
|
|
69
|
-
return { value: JSON.parse(text) };
|
|
70
|
-
}
|
|
71
|
-
catch (err) {
|
|
72
|
-
if (err instanceof SyntaxError)
|
|
73
|
-
return undefined;
|
|
74
|
-
throw err;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/** One wire line's text: {@link readWireValue} of its JSON, or `malformed` when it is not JSON. */
|
|
78
|
-
export function readWireLine(lines, text) {
|
|
79
|
-
const json = jsonValue(text);
|
|
80
|
-
// labels-exempt: internal diagnostic; the user reads session.part_skipped
|
|
81
|
-
return json ? readWireValue(lines, json.value) : malformed('a line is not JSON');
|
|
82
|
-
}
|
|
83
|
-
/** A whole reply's JSON text as a value; text that is not JSON is `bad_response`. */
|
|
84
|
-
export function parseWireJson(text) {
|
|
85
|
-
const json = jsonValue(text);
|
|
86
|
-
// labels-exempt: internal diagnostic; the user reads error.bad_response
|
|
87
|
-
if (!json)
|
|
88
|
-
throw new TheoremError('bad_response', 'a line is not JSON');
|
|
89
|
-
return json.value;
|
|
90
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AudioWorklet processor that forwards mono mic frames to the main thread.
|
|
3
|
-
* Plain JS: it runs in the AudioWorkletGlobalScope as its own module, loaded
|
|
4
|
-
* by URL (see `../mic-capture.ts`), so it imports nothing and ships as is.
|
|
5
|
-
*/
|
|
6
|
-
registerProcessor(
|
|
7
|
-
'mic-capture-processor',
|
|
8
|
-
class MicCaptureProcessor extends AudioWorkletProcessor {
|
|
9
|
-
process(inputs) {
|
|
10
|
-
const channel = inputs[0][0];
|
|
11
|
-
const copy = new Float32Array(channel);
|
|
12
|
-
this.port.postMessage(copy, [copy.buffer]);
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
);
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import type { AttachmentValidationIssue, ComposerMenuAction, ComposerPendingMessage, ComposerProfileInterface, ComposerRunPhase, InterfaceTurnSession, TranscriptBlock } from '@theoremjs/agents/interface';
|
|
2
|
-
import { type MutableRefObject } from 'react';
|
|
3
|
-
import { type ClientFailure } from '../client/failure.ts';
|
|
4
|
-
import { type AnsweringGate, type StreamView, type ToolDecisionAction, type ToolGateResolution } from '../client/index.ts';
|
|
5
|
-
import type { RunOutcome } from '../client/run-session.ts';
|
|
6
|
-
import type { TheoremTransport } from '../client/transport.ts';
|
|
7
|
-
import type { MessageDelivery } from './use-theorem-chat-state.ts';
|
|
8
|
-
export type RunTurnStream = (run: (view: StreamView) => Promise<RunOutcome>, options?: {
|
|
9
|
-
/** The run sends a message: one that never posts goes back in the composer with its failure. */
|
|
10
|
-
message?: {
|
|
11
|
-
restore(): Promise<void>;
|
|
12
|
-
};
|
|
13
|
-
}) => Promise<void>;
|
|
14
|
-
export type TheoremChatActionArgs = {
|
|
15
|
-
iface: ComposerProfileInterface | null;
|
|
16
|
-
transport: TheoremTransport;
|
|
17
|
-
phase: ComposerRunPhase;
|
|
18
|
-
gated: boolean;
|
|
19
|
-
draftText: string;
|
|
20
|
-
pendingFiles: File[];
|
|
21
|
-
pendingVoice: File[];
|
|
22
|
-
/** The composer as it is now, for a run that ends after it changed. */
|
|
23
|
-
composerRef: MutableRefObject<{
|
|
24
|
-
draftText: string;
|
|
25
|
-
pendingFiles: File[];
|
|
26
|
-
pendingVoice: File[];
|
|
27
|
-
}>;
|
|
28
|
-
/** The ref of the conversation the chat continues; none before its first message posts. */
|
|
29
|
-
conversationRef: MutableRefObject<string | undefined>;
|
|
30
|
-
clearComposer: () => void;
|
|
31
|
-
runTurnStream: RunTurnStream;
|
|
32
|
-
sessionRef: MutableRefObject<InterfaceTurnSession>;
|
|
33
|
-
blocksRef: MutableRefObject<TranscriptBlock[]>;
|
|
34
|
-
abortRef: MutableRefObject<AbortController | null>;
|
|
35
|
-
turnIdRef: MutableRefObject<string | null>;
|
|
36
|
-
busyRef: MutableRefObject<boolean>;
|
|
37
|
-
runPromiseRef: MutableRefObject<Promise<void> | null>;
|
|
38
|
-
allowQueueDrainRef: MutableRefObject<boolean>;
|
|
39
|
-
setBlocks: (value: TranscriptBlock[] | ((prev: TranscriptBlock[]) => TranscriptBlock[])) => void;
|
|
40
|
-
setStreamBlocks: (value: TranscriptBlock[]) => void;
|
|
41
|
-
setSession: (value: InterfaceTurnSession) => void;
|
|
42
|
-
setChatStarted: (value: boolean) => void;
|
|
43
|
-
setStreaming: (value: boolean) => void;
|
|
44
|
-
setPendingMessages: (value: ComposerPendingMessage[] | ((prev: ComposerPendingMessage[]) => ComposerPendingMessage[])) => void;
|
|
45
|
-
setDraftText: (value: string) => void;
|
|
46
|
-
setPendingFiles: (value: File[]) => void;
|
|
47
|
-
setPendingVoice: (value: File[]) => void;
|
|
48
|
-
setIssues: (value: AttachmentValidationIssue[]) => void;
|
|
49
|
-
setFailure: (value: ClientFailure | null) => void;
|
|
50
|
-
setAnswering: (value: AnsweringGate | null) => void;
|
|
51
|
-
setDelivery: (value: {
|
|
52
|
-
status: MessageDelivery;
|
|
53
|
-
} | null) => void;
|
|
54
|
-
pendingRef: MutableRefObject<ComposerPendingMessage[]>;
|
|
55
|
-
};
|
|
56
|
-
type ComposerFields = {
|
|
57
|
-
text: string;
|
|
58
|
-
files: File[];
|
|
59
|
-
voice: File[];
|
|
60
|
-
};
|
|
61
|
-
export declare function useTheoremChatActions(args: TheoremChatActionArgs): {
|
|
62
|
-
startTurnFromFields: (fields: ComposerFields) => Promise<void>;
|
|
63
|
-
startTurnFromDraft: (draft: ComposerPendingMessage["draft"], options?: {
|
|
64
|
-
/** Send while the reply waits on gates: the message walks away from them. */
|
|
65
|
-
walkAway?: boolean;
|
|
66
|
-
/** Once the message posts: it leaves wherever it was waiting to be sent. */
|
|
67
|
-
onPosted?: () => void;
|
|
68
|
-
}) => Promise<void>;
|
|
69
|
-
handleStop: () => void;
|
|
70
|
-
handleSubmit: () => Promise<void>;
|
|
71
|
-
handleSendNow: (draftSource?: ComposerPendingMessage) => Promise<void>;
|
|
72
|
-
handleMenuAction: (action: ComposerMenuAction) => void;
|
|
73
|
-
handleToolDecision: (_index: number, action: ToolDecisionAction) => Promise<void>;
|
|
74
|
-
handleAuthenticated: (_index: number, secret?: string) => Promise<void>;
|
|
75
|
-
resumeGatedTool: (resolution: ToolGateResolution) => Promise<void>;
|
|
76
|
-
handlePendingRestore: (id: string) => Promise<void>;
|
|
77
|
-
enqueuePending: (kind: "queue" | "steer" | "stash") => Promise<void>;
|
|
78
|
-
};
|
|
79
|
-
export {};
|
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
import { TheoremError } from '@theoremjs/agents';
|
|
2
|
-
import { convertSteersToFrontQueued, createComposerPendingMessage, orderComposerPendingMessages, removeComposerPendingMessage, userDraftHasPayload, userDraftToSteerInject, } from '@theoremjs/agents/interface';
|
|
3
|
-
import { useCallback } from 'react';
|
|
4
|
-
import { clientFailure } from "../client/failure.js";
|
|
5
|
-
import { composerFieldsFromDraft, encodeComposerDraft, resumeInterfaceTool, streamInterfaceDraftTurn, streamInterfaceTurn, } from "../client/index.js";
|
|
6
|
-
import { issuedOperationId } from "../client/turn-client.js";
|
|
7
|
-
function composerFieldsPayload(text, pendingFiles, pendingVoice) {
|
|
8
|
-
const meta = (files) => files.map((f) => ({
|
|
9
|
-
name: f.name,
|
|
10
|
-
mimeType: f.type || 'application/octet-stream',
|
|
11
|
-
sizeBytes: f.size,
|
|
12
|
-
}));
|
|
13
|
-
return {
|
|
14
|
-
...(text.trim() ? { text } : {}),
|
|
15
|
-
...(pendingFiles.length ? { attachments: meta(pendingFiles) } : {}),
|
|
16
|
-
...(pendingVoice.length ? { voice: meta(pendingVoice) } : {}),
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
function newTurnId() {
|
|
20
|
-
return typeof crypto !== 'undefined' && 'randomUUID' in crypto
|
|
21
|
-
? crypto.randomUUID()
|
|
22
|
-
: `turn-${Date.now()}`;
|
|
23
|
-
}
|
|
24
|
-
function beginAbortableTurn(args) {
|
|
25
|
-
if (!args.iface)
|
|
26
|
-
return null;
|
|
27
|
-
const controller = new AbortController();
|
|
28
|
-
args.abortRef.current = controller;
|
|
29
|
-
const turnId = newTurnId();
|
|
30
|
-
args.turnIdRef.current = turnId;
|
|
31
|
-
return {
|
|
32
|
-
composer: args.iface,
|
|
33
|
-
turnId,
|
|
34
|
-
signal: controller.signal,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
/** The run's scope: the conversation the chat continues, and the run's own turn. */
|
|
38
|
-
function scopeOf(args, turnId) {
|
|
39
|
-
return { conversation: args.conversationRef.current, turnId };
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Puts a message back in the composer. What the composer holds now is
|
|
43
|
-
* stashed first, so nothing the user typed is lost.
|
|
44
|
-
*/
|
|
45
|
-
function useRestoreToComposer(args) {
|
|
46
|
-
return useCallback(async (fields) => {
|
|
47
|
-
const { draftText, pendingFiles, pendingVoice } = args.composerRef.current;
|
|
48
|
-
if (userDraftHasPayload(composerFieldsPayload(draftText, pendingFiles, pendingVoice))) {
|
|
49
|
-
const draft = await encodeComposerDraft({ text: draftText, pendingFiles, pendingVoice });
|
|
50
|
-
const stash = createComposerPendingMessage({ kind: 'stash', draft });
|
|
51
|
-
args.setPendingMessages((prev) => orderComposerPendingMessages([...prev, stash]));
|
|
52
|
-
}
|
|
53
|
-
args.setDraftText(fields.text);
|
|
54
|
-
args.setPendingFiles(fields.files);
|
|
55
|
-
args.setPendingVoice(fields.voice);
|
|
56
|
-
args.setIssues([]);
|
|
57
|
-
}, [args]);
|
|
58
|
-
}
|
|
59
|
-
/** Starts a turn from the composer's fields, or from an encoded draft (queued or send-now). */
|
|
60
|
-
function useTurnStarters(args, restoreToComposer) {
|
|
61
|
-
const startTurnFromFields = useCallback(async (fields) => {
|
|
62
|
-
const started = beginAbortableTurn(args);
|
|
63
|
-
if (!started)
|
|
64
|
-
return;
|
|
65
|
-
await args.runTurnStream((view) => streamInterfaceTurn({
|
|
66
|
-
iface: started.composer,
|
|
67
|
-
transport: args.transport,
|
|
68
|
-
session: args.sessionRef.current,
|
|
69
|
-
text: fields.text,
|
|
70
|
-
pendingFiles: fields.files,
|
|
71
|
-
pendingVoice: fields.voice,
|
|
72
|
-
signal: started.signal,
|
|
73
|
-
scope: scopeOf(args, started.turnId),
|
|
74
|
-
view,
|
|
75
|
-
transcript: args.blocksRef.current,
|
|
76
|
-
onUserBlocks: (userBlocks) => {
|
|
77
|
-
args.setBlocks((prev) => [...prev, ...userBlocks]);
|
|
78
|
-
args.setDelivery({ status: 'sending' });
|
|
79
|
-
args.setChatStarted(true);
|
|
80
|
-
args.setStreaming(true);
|
|
81
|
-
args.clearComposer();
|
|
82
|
-
},
|
|
83
|
-
}), { message: { restore: () => restoreToComposer(fields) } });
|
|
84
|
-
}, [args, restoreToComposer]);
|
|
85
|
-
const startTurnFromDraft = useCallback(async (draft, options = {}) => {
|
|
86
|
-
const started = beginAbortableTurn(args);
|
|
87
|
-
if (!started)
|
|
88
|
-
return;
|
|
89
|
-
await args.runTurnStream((view) => streamInterfaceDraftTurn({
|
|
90
|
-
iface: started.composer,
|
|
91
|
-
transport: args.transport,
|
|
92
|
-
session: args.sessionRef.current,
|
|
93
|
-
draft,
|
|
94
|
-
signal: started.signal,
|
|
95
|
-
scope: scopeOf(args, started.turnId),
|
|
96
|
-
view,
|
|
97
|
-
transcript: args.blocksRef.current,
|
|
98
|
-
walkAway: options.walkAway === true,
|
|
99
|
-
onUserBlocks: (posted) => {
|
|
100
|
-
args.setBlocks((prev) => [...prev, ...posted]);
|
|
101
|
-
args.setStreamBlocks([]);
|
|
102
|
-
args.setDelivery({ status: 'sending' });
|
|
103
|
-
args.setChatStarted(true);
|
|
104
|
-
args.setStreaming(true);
|
|
105
|
-
options.onPosted?.();
|
|
106
|
-
},
|
|
107
|
-
}), { message: { restore: () => restoreToComposer(composerFieldsFromDraft(draft)) } });
|
|
108
|
-
}, [args, restoreToComposer]);
|
|
109
|
-
return { startTurnFromFields, startTurnFromDraft };
|
|
110
|
-
}
|
|
111
|
-
/** A steer with no running turn: the user reads `session.turn_ended`; queued steers move to the front. */
|
|
112
|
-
function steerAfterTurnEnded(args, messageId) {
|
|
113
|
-
args.setFailure(clientFailure(
|
|
114
|
-
// labels-exempt: internal diagnostic; the user reads session.turn_ended
|
|
115
|
-
new TheoremError('request', 'steer: no active turn', { copy: { key: 'session.turn_ended' } }), args.iface?.labels));
|
|
116
|
-
args.setPendingMessages((prev) => orderComposerPendingMessages(convertSteersToFrontQueued(removeComposerPendingMessage(prev, messageId))));
|
|
117
|
-
}
|
|
118
|
-
/** Queue / steer / stash the composer draft, and restore a pending message into the composer. */
|
|
119
|
-
function usePendingActions(args, restoreToComposer) {
|
|
120
|
-
const enqueuePending = useCallback(async (kind) => {
|
|
121
|
-
if (!userDraftHasPayload(composerFieldsPayload(args.draftText, args.pendingFiles, args.pendingVoice))) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
args.setIssues([]);
|
|
125
|
-
try {
|
|
126
|
-
const draft = await encodeComposerDraft({
|
|
127
|
-
text: args.draftText,
|
|
128
|
-
pendingFiles: args.pendingFiles,
|
|
129
|
-
pendingVoice: args.pendingVoice,
|
|
130
|
-
});
|
|
131
|
-
const message = createComposerPendingMessage({ kind, draft });
|
|
132
|
-
args.setPendingMessages((prev) => orderComposerPendingMessages([...prev, message]));
|
|
133
|
-
args.clearComposer();
|
|
134
|
-
if (kind !== 'steer')
|
|
135
|
-
return;
|
|
136
|
-
const turnId = args.turnIdRef.current;
|
|
137
|
-
if (!turnId) {
|
|
138
|
-
steerAfterTurnEnded(args, message.id);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
const inject = userDraftToSteerInject(draft);
|
|
142
|
-
if (inject.length === 0)
|
|
143
|
-
return;
|
|
144
|
-
await args.transport.steer({ turnId, id: message.id, inject });
|
|
145
|
-
}
|
|
146
|
-
catch (err) {
|
|
147
|
-
args.setFailure(clientFailure(err, args.iface?.labels));
|
|
148
|
-
}
|
|
149
|
-
}, [args]);
|
|
150
|
-
const handlePendingRestore = useCallback(async (id) => {
|
|
151
|
-
const message = args.pendingRef.current.find((m) => m.id === id);
|
|
152
|
-
if (!message)
|
|
153
|
-
return;
|
|
154
|
-
try {
|
|
155
|
-
await restoreToComposer(composerFieldsFromDraft(message.draft));
|
|
156
|
-
args.setPendingMessages((prev) => removeComposerPendingMessage(prev, id));
|
|
157
|
-
}
|
|
158
|
-
catch (err) {
|
|
159
|
-
args.setFailure(clientFailure(err, args.iface?.labels));
|
|
160
|
-
}
|
|
161
|
-
}, [args, restoreToComposer]);
|
|
162
|
-
return { enqueuePending, handlePendingRestore };
|
|
163
|
-
}
|
|
164
|
-
/** Answer the gate the session waits on: a decision, or a sign-in. */
|
|
165
|
-
function useGateActions(args) {
|
|
166
|
-
const resumeGatedTool = useCallback(async (resolution) => {
|
|
167
|
-
const composer = args.iface;
|
|
168
|
-
if (!composer)
|
|
169
|
-
return;
|
|
170
|
-
// why: Set once the run starts (not while another runs), and cleared once it has ended.
|
|
171
|
-
let started = false;
|
|
172
|
-
try {
|
|
173
|
-
await args.runTurnStream((view) => {
|
|
174
|
-
started = true;
|
|
175
|
-
const session = args.sessionRef.current;
|
|
176
|
-
// why: A person's answer shows on its gate while it settles; the page's has no gate to show on.
|
|
177
|
-
if (session.gatedTool && resolution.action !== 'page')
|
|
178
|
-
args.setAnswering({
|
|
179
|
-
callId: session.gatedTool.callId,
|
|
180
|
-
operationId: issuedOperationId(session.gatedTool),
|
|
181
|
-
action: resolution.action,
|
|
182
|
-
});
|
|
183
|
-
return resumeInterfaceTool({
|
|
184
|
-
iface: composer,
|
|
185
|
-
transport: args.transport,
|
|
186
|
-
session,
|
|
187
|
-
scope: scopeOf(args),
|
|
188
|
-
resolution,
|
|
189
|
-
view,
|
|
190
|
-
});
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
finally {
|
|
194
|
-
if (started)
|
|
195
|
-
args.setAnswering(null);
|
|
196
|
-
}
|
|
197
|
-
}, [args]);
|
|
198
|
-
const handleToolDecision = useCallback(async (_index, action) => {
|
|
199
|
-
await resumeGatedTool({ action });
|
|
200
|
-
}, [resumeGatedTool]);
|
|
201
|
-
const handleAuthenticated = useCallback(async (_index, secret) => {
|
|
202
|
-
await resumeGatedTool({ action: 'auth', ...(secret === undefined ? {} : { secret }) });
|
|
203
|
-
}, [resumeGatedTool]);
|
|
204
|
-
return { handleToolDecision, handleAuthenticated, resumeGatedTool };
|
|
205
|
-
}
|
|
206
|
-
export function useTheoremChatActions(args) {
|
|
207
|
-
const restoreToComposer = useRestoreToComposer(args);
|
|
208
|
-
const { startTurnFromFields, startTurnFromDraft } = useTurnStarters(args, restoreToComposer);
|
|
209
|
-
const { enqueuePending, handlePendingRestore } = usePendingActions(args, restoreToComposer);
|
|
210
|
-
const { handleToolDecision, handleAuthenticated, resumeGatedTool } = useGateActions(args);
|
|
211
|
-
const handleStop = useCallback(() => {
|
|
212
|
-
args.abortRef.current?.abort();
|
|
213
|
-
}, [args]);
|
|
214
|
-
const handleSubmit = useCallback(async () => {
|
|
215
|
-
if (args.phase === 'streaming' || args.phase === 'gated') {
|
|
216
|
-
await enqueuePending('queue');
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
if (args.gated)
|
|
220
|
-
return;
|
|
221
|
-
args.setIssues([]);
|
|
222
|
-
await startTurnFromFields({
|
|
223
|
-
text: args.draftText,
|
|
224
|
-
files: [...args.pendingFiles],
|
|
225
|
-
voice: [...args.pendingVoice],
|
|
226
|
-
});
|
|
227
|
-
}, [args, enqueuePending, startTurnFromFields]);
|
|
228
|
-
/** The queued message's draft, or the composer's when it holds something to send. */
|
|
229
|
-
const draftToSend = useCallback(async (draftSource) => {
|
|
230
|
-
if (draftSource)
|
|
231
|
-
return draftSource.draft;
|
|
232
|
-
const draft = await encodeComposerDraft({
|
|
233
|
-
text: args.draftText,
|
|
234
|
-
pendingFiles: args.pendingFiles,
|
|
235
|
-
pendingVoice: args.pendingVoice,
|
|
236
|
-
});
|
|
237
|
-
return userDraftHasPayload(draft) ? draft : undefined;
|
|
238
|
-
}, [args]);
|
|
239
|
-
/** The sent message leaves the queue, or the composer it came from. */
|
|
240
|
-
const releaseDraft = useCallback((draftSource) => {
|
|
241
|
-
if (!draftSource) {
|
|
242
|
-
args.clearComposer();
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
const pendingId = draftSource.id;
|
|
246
|
-
args.setPendingMessages((prev) => removeComposerPendingMessage(prev, pendingId));
|
|
247
|
-
}, [args]);
|
|
248
|
-
const handleSendNow = useCallback(async (draftSource) => {
|
|
249
|
-
if (!args.iface)
|
|
250
|
-
return;
|
|
251
|
-
const draft = await draftToSend(draftSource);
|
|
252
|
-
if (!draft)
|
|
253
|
-
return;
|
|
254
|
-
if (args.busyRef.current) {
|
|
255
|
-
args.abortRef.current?.abort();
|
|
256
|
-
await args.runPromiseRef.current;
|
|
257
|
-
}
|
|
258
|
-
args.setPendingMessages((prev) => convertSteersToFrontQueued(prev));
|
|
259
|
-
args.allowQueueDrainRef.current = false;
|
|
260
|
-
// why: Sent while the reply waits on gates, the message walks away from them in its own request.
|
|
261
|
-
await startTurnFromDraft(draft, {
|
|
262
|
-
walkAway: args.sessionRef.current.gatedTool !== null,
|
|
263
|
-
onPosted: () => releaseDraft(draftSource),
|
|
264
|
-
});
|
|
265
|
-
}, [args, draftToSend, releaseDraft, startTurnFromDraft]);
|
|
266
|
-
const handleMenuAction = useCallback((action) => {
|
|
267
|
-
if (action === 'queue' || action === 'steer' || action === 'stash') {
|
|
268
|
-
void enqueuePending(action);
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
if (action === 'send_now')
|
|
272
|
-
void handleSendNow();
|
|
273
|
-
}, [enqueuePending, handleSendNow]);
|
|
274
|
-
return {
|
|
275
|
-
startTurnFromFields,
|
|
276
|
-
startTurnFromDraft,
|
|
277
|
-
handleStop,
|
|
278
|
-
handleSubmit,
|
|
279
|
-
handleSendNow,
|
|
280
|
-
handleMenuAction,
|
|
281
|
-
handleToolDecision,
|
|
282
|
-
handleAuthenticated,
|
|
283
|
-
resumeGatedTool,
|
|
284
|
-
handlePendingRestore,
|
|
285
|
-
enqueuePending,
|
|
286
|
-
};
|
|
287
|
-
}
|