@candor-ui/react 1.3.0 → 1.7.0
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/dist/adapters/ag-ui.d.ts +81 -16
- package/dist/adapters/ag-ui.js +308 -1
- package/dist/adapters/ai-sdk.d.ts +11 -6
- package/dist/adapters/ai-sdk.js +18 -1
- package/dist/adapters/claude-agent-sdk.d.ts +123 -14
- package/dist/adapters/claude-agent-sdk.js +163 -5
- package/dist/adapters/claude-agent-server.d.ts +199 -14
- package/dist/adapters/claude-agent-server.js +448 -49
- package/dist/adapters/use-ag-ui.d.ts +12 -6
- package/dist/adapters/use-ag-ui.js +23 -5
- package/dist/adapters/use-candor-chat.d.ts +1 -1
- package/dist/adapters/use-candor-chat.js +3 -3
- package/dist/adapters/use-claude-agent.d.ts +38 -9
- package/dist/adapters/use-claude-agent.js +96 -20
- package/dist/blocks/copy-field.d.ts +1 -1
- package/dist/blocks/copy-field.js +1 -1
- package/dist/blocks/degraded-panel.d.ts +5 -5
- package/dist/blocks/locale.d.ts +6 -6
- package/dist/blocks/locked.d.ts +8 -8
- package/dist/blocks/relative-time.d.ts +6 -6
- package/dist/blocks/status-dot.d.ts +3 -3
- package/dist/blocks/step-list.d.ts +3 -3
- package/dist/blocks/streaming-text.d.ts +3 -3
- package/dist/chat/agent-avatar.d.ts +4 -4
- package/dist/chat/ai-disclosure.d.ts +37 -0
- package/dist/chat/ai-disclosure.js +48 -0
- package/dist/chat/attachment-preview.d.ts +6 -6
- package/dist/chat/attachment-preview.js +2 -2
- package/dist/chat/card-registry.js +1 -1
- package/dist/chat/citation.d.ts +3 -3
- package/dist/chat/citation.js +6 -4
- package/dist/chat/composer.d.ts +31 -20
- package/dist/chat/composer.js +10 -6
- package/dist/chat/context-meter.d.ts +1 -1
- package/dist/chat/context-meter.js +1 -1
- package/dist/chat/entity-chip.d.ts +3 -3
- package/dist/chat/entity-chip.js +1 -1
- package/dist/chat/folded-turns.d.ts +11 -6
- package/dist/chat/folded-turns.js +2 -2
- package/dist/chat/message-actions.d.ts +6 -6
- package/dist/chat/message-actions.js +1 -1
- package/dist/chat/message-content.d.ts +13 -7
- package/dist/chat/message-content.js +10 -5
- package/dist/chat/message.d.ts +64 -37
- package/dist/chat/message.js +17 -11
- package/dist/chat/payload.d.ts +4 -4
- package/dist/chat/payload.js +5 -2
- package/dist/chat/permission-prompt.d.ts +129 -0
- package/dist/chat/permission-prompt.js +144 -0
- package/dist/chat/prompt-suggestions.d.ts +4 -4
- package/dist/chat/prompt-suggestions.js +1 -1
- package/dist/chat/reasoning.d.ts +3 -3
- package/dist/chat/reasoning.js +1 -1
- package/dist/chat/thread-divider.d.ts +3 -3
- package/dist/chat/thread-event.d.ts +10 -5
- package/dist/chat/thread-event.js +3 -2
- package/dist/chat/thread.d.ts +23 -7
- package/dist/chat/thread.js +29 -6
- package/dist/chat/tool-call.d.ts +7 -2
- package/dist/chat/tool-call.js +8 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/lib/chat.d.ts +53 -38
- package/dist/lib/know.d.ts +14 -12
- package/dist/lib/render-prop.d.ts +4 -4
- package/dist/lib/safe-markdown.d.ts +1 -1
- package/dist/lib/status.d.ts +21 -0
- package/dist/lib/status.js +17 -0
- package/dist/lib/use-shortcut.d.ts +1 -1
- package/dist/lib/use-virtual-list.d.ts +6 -6
- package/dist/styles.css +4 -1
- package/dist/ui/button.d.ts +1 -1
- package/dist/ui/button.js +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,123 @@
|
|
|
1
|
-
import type { CanUseTool, Query, SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
-
import type
|
|
1
|
+
import type { CanUseTool, PermissionMode, Query, SDKMessage } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
+
import { type AgentEvent, type ClaudeApproval, type ClaudeApprovalAnswer, type ClaudePermissionMode } from "./claude-agent-sdk.js";
|
|
3
|
+
import type { EntityRef } from "../lib/chat.js";
|
|
4
|
+
/** A permission request as a store keeps it. */
|
|
5
|
+
export type StoredApproval = {
|
|
6
|
+
id: string;
|
|
7
|
+
/** The run it belongs to, when the run has an id. */
|
|
8
|
+
runId?: string | undefined;
|
|
9
|
+
/** Who may answer it; checked by answerClaudeApproval. */
|
|
10
|
+
owner?: string | undefined;
|
|
11
|
+
request: ClaudeApproval;
|
|
12
|
+
createdAt: string;
|
|
13
|
+
/** Set once answered. Recorded, not necessarily used: a run that stopped at the same moment still denies the tool. */
|
|
14
|
+
answer?: ClaudeApprovalAnswer & {
|
|
15
|
+
at: string;
|
|
16
|
+
} | undefined;
|
|
17
|
+
/** Set when nobody can answer any more (the run ended or stopped), with why. */
|
|
18
|
+
closed?: {
|
|
19
|
+
at: string;
|
|
20
|
+
reason: string;
|
|
21
|
+
} | undefined;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Where waiting permission requests live. Answering and closing each happen once: whichever comes first wins, so a
|
|
25
|
+
* late answer to a run that already ended returns false instead of being lost. A store backed by a database does
|
|
26
|
+
* both as one conditional update (`… where answered_at is null and closed_at is null`).
|
|
27
|
+
*/
|
|
28
|
+
export interface ApprovalStore {
|
|
29
|
+
/** Record a request that waits on a person. */
|
|
30
|
+
put(approval: StoredApproval): Promise<void>;
|
|
31
|
+
get(id: string): Promise<StoredApproval | undefined>;
|
|
32
|
+
/** Record the answer. False when there's no such request, or it was already answered or closed. */
|
|
33
|
+
answer(id: string, answer: ClaudeApprovalAnswer): Promise<boolean>;
|
|
34
|
+
/** Mark that it can't be answered any more. False when it was answered first. */
|
|
35
|
+
close(id: string, reason: string): Promise<boolean>;
|
|
36
|
+
/**
|
|
37
|
+
* Resolves with the answer once there is one, or undefined once it's closed or `signal` aborts. When `signal`
|
|
38
|
+
* aborts first, close the request in the same step ("The run was stopped."), so an answer arriving just after is
|
|
39
|
+
* refused instead of recorded for a tool that never ran. A store with no way to push can poll with waitByPolling.
|
|
40
|
+
*/
|
|
41
|
+
wait(id: string, signal: AbortSignal): Promise<ClaudeApprovalAnswer | undefined>;
|
|
42
|
+
/** Requests still waiting, oldest first, for one run or all: what to show again after a reload. */
|
|
43
|
+
pending(runId?: string): Promise<StoredApproval[]>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The default ApprovalStore: this process's memory. Answered and closed requests are forgotten after `keepMs`
|
|
47
|
+
* (10 minutes), so it doesn't grow without bound.
|
|
48
|
+
*/
|
|
49
|
+
export declare function memoryApprovalStore({ keepMs }?: {
|
|
50
|
+
keepMs?: number | undefined;
|
|
51
|
+
}): ApprovalStore;
|
|
52
|
+
/** A `wait` for stores that can't push: reads the request every `intervalMs` (1s) until it's answered or closed. */
|
|
53
|
+
export declare function waitByPolling(get: (id: string) => Promise<StoredApproval | undefined>, id: string, signal: AbortSignal, intervalMs?: number): Promise<ClaudeApprovalAnswer | undefined>;
|
|
54
|
+
export type ClaudeCanUseToolOptions = {
|
|
55
|
+
/** Where requests wait. Defaults to this process's memory. */
|
|
56
|
+
approvals?: ApprovalStore | undefined;
|
|
57
|
+
/** Sends each request, and its closing, to whoever shows it (the browser, your event log). */
|
|
58
|
+
emit: (event: AgentEvent) => void;
|
|
59
|
+
/** Who may answer. */
|
|
60
|
+
owner?: string | undefined;
|
|
61
|
+
/** The run's id, kept with each request. */
|
|
62
|
+
runId?: string | undefined;
|
|
63
|
+
/** The run's permission mode now, recorded on each request. */
|
|
64
|
+
mode?: (() => ClaudePermissionMode | undefined) | undefined;
|
|
65
|
+
/** Called with each request's id as it starts waiting and once it's settled, e.g. to close the rest when the run ends. */
|
|
66
|
+
track?: {
|
|
67
|
+
add(id: string): void;
|
|
68
|
+
delete(id: string): void;
|
|
69
|
+
} | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Which tools' input a person may edit before allowing it (`updatedInput`). Every tool by default, as in 1.5.0;
|
|
72
|
+
* an answer that edits a tool this refuses is rejected by answerClaudeApproval, whatever the browser sends.
|
|
73
|
+
*/
|
|
74
|
+
editable?: ((tool: string, input: unknown) => boolean) | undefined;
|
|
75
|
+
/** Close a request nobody answered after this long, as expired: the tool is denied, never allowed. No limit by default. */
|
|
76
|
+
approvalTimeoutMs?: number | undefined;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* A canUseTool that keeps each request in an ApprovalStore and waits for its answer from wherever it's given: your
|
|
80
|
+
* route, a queue, a workflow signal (`approvals.answer(id, { approved: true })`). Use it on its own when your agent
|
|
81
|
+
* runs somewhere other than streamClaudeAgent. When the SDK stops waiting, the request is closed, so a late answer
|
|
82
|
+
* is refused rather than lost.
|
|
83
|
+
*/
|
|
84
|
+
export declare function claudeCanUseTool({ approvals, emit, owner, runId, mode, track, editable, approvalTimeoutMs }: ClaudeCanUseToolOptions): CanUseTool;
|
|
85
|
+
/**
|
|
86
|
+
* A run's events, kept so a browser can re-attach after a reload and a finished run can be replayed. `read` returns
|
|
87
|
+
* the events from index `from` on, and whether the run has ended.
|
|
88
|
+
*/
|
|
89
|
+
export interface ClaudeRunStore {
|
|
90
|
+
/**
|
|
91
|
+
* Begin a run, with who started it. streamClaudeAgent calls it first. An append, end or subscribe for a run that
|
|
92
|
+
* was never started (or was already forgotten) must do nothing rather than create it, so a forgotten run can't
|
|
93
|
+
* come back without its owner.
|
|
94
|
+
*/
|
|
95
|
+
start?(runId: string, owner?: string): Promise<void>;
|
|
96
|
+
append(runId: string, event: AgentEvent): Promise<void>;
|
|
97
|
+
end(runId: string): Promise<void>;
|
|
98
|
+
read(runId: string, from: number): Promise<{
|
|
99
|
+
events: AgentEvent[];
|
|
100
|
+
ended: boolean;
|
|
101
|
+
} | undefined>;
|
|
102
|
+
/** Called when the run has new events or ends. Optional: without it, attaching polls `read`. */
|
|
103
|
+
subscribe?(runId: string, listener: () => void): () => void;
|
|
104
|
+
/** Who started the run, when it was started with an owner; attachClaudeAgentRun checks it. */
|
|
105
|
+
ownerOf?(runId: string): Promise<string | undefined>;
|
|
106
|
+
/** Record the run's owner. Kept from 1.5.0; prefer `start`. */
|
|
107
|
+
setOwner?(runId: string, owner: string): Promise<void>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* The default ClaudeRunStore: this process's memory. It keeps at most `maxRuns` finished runs (100), forgetting the
|
|
111
|
+
* oldest finished one first; a run still going is never forgotten. Each run keeps at most `maxEvents` events
|
|
112
|
+
* (5,000): past that, partial-text events are no longer kept (the finished message still is), so a re-attached
|
|
113
|
+
* browser sees text arrive a message at a time instead of as it streams.
|
|
114
|
+
*/
|
|
115
|
+
export declare function memoryRunStore({ maxRuns, maxEvents }?: {
|
|
116
|
+
maxRuns?: number | undefined;
|
|
117
|
+
maxEvents?: number | undefined;
|
|
118
|
+
}): ClaudeRunStore;
|
|
119
|
+
/** Which permission modes a run may be switched to: a list, or a test. */
|
|
120
|
+
export type ModePolicy = readonly PermissionMode[] | ((mode: PermissionMode) => boolean);
|
|
3
121
|
export type RunClaudeAgent = (tools: {
|
|
4
122
|
/** Pass to query()'s `canUseTool`, so permission requests reach the person. */
|
|
5
123
|
canUseTool: CanUseTool;
|
|
@@ -10,20 +128,52 @@ export type RunClaudeAgent = (tools: {
|
|
|
10
128
|
* It renders through the app's card registry, in the reply where it was sent.
|
|
11
129
|
*/
|
|
12
130
|
emit: (event: AgentEvent) => void;
|
|
131
|
+
/** This run's id: the same one the response's `x-candor-run-id` header carries. */
|
|
132
|
+
runId: string;
|
|
13
133
|
}) => Query;
|
|
14
134
|
export type StreamClaudeAgentOptions = {
|
|
15
|
-
/** The incoming request's signal (`request.signal`): the agent stops when the browser goes away
|
|
16
|
-
signal?: AbortSignal;
|
|
17
|
-
/** Who may answer this run's permission requests, e.g. the signed-in user's id. Checked
|
|
18
|
-
owner?: string;
|
|
135
|
+
/** The incoming request's signal (`request.signal`): the agent stops when the browser goes away, unless `detach`. */
|
|
136
|
+
signal?: AbortSignal | undefined;
|
|
137
|
+
/** Who may answer this run's permission requests, e.g. the signed-in user's id. Checked when they're answered. */
|
|
138
|
+
owner?: string | undefined;
|
|
19
139
|
/** The sentence shown when the run fails. Defaults to a generic one, so server errors don't leak to the browser. */
|
|
20
|
-
describeError?: (error: unknown) => string;
|
|
140
|
+
describeError?: ((error: unknown) => string) | undefined;
|
|
21
141
|
/**
|
|
22
142
|
* Called with every SDK message just before it's sent to the browser, e.g. to record usage and cost from
|
|
23
143
|
* `assistant` and `result` messages. To stop the run from here, abort the run's abortController: the message
|
|
24
144
|
* in hand is still sent, and nothing after it.
|
|
25
145
|
*/
|
|
26
|
-
onMessage?: (message: SDKMessage) => void | Promise<void
|
|
146
|
+
onMessage?: ((message: SDKMessage) => void | Promise<void>) | undefined;
|
|
147
|
+
/** Called with every event the browser gets, in order, e.g. to keep the whole conversation for replay. */
|
|
148
|
+
onEvent?: ((event: AgentEvent) => void | Promise<void>) | undefined;
|
|
149
|
+
/** Where permission requests wait. Defaults to this process's memory. */
|
|
150
|
+
approvals?: ApprovalStore | undefined;
|
|
151
|
+
/** Keeps the run's events so a browser can re-attach (attachClaudeAgentRun). Without it, a reload loses the run. */
|
|
152
|
+
runs?: ClaudeRunStore | undefined;
|
|
153
|
+
/** The run's id; a new one by default. Sent back in the `x-candor-run-id` header. */
|
|
154
|
+
runId?: string | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Keep running when the browser goes away (a reload, a closed tab), so it can re-attach. Stop it with
|
|
157
|
+
* stopClaudeAgentRun. Needs a process that outlives the response: not a serverless function that's frozen when
|
|
158
|
+
* the response ends.
|
|
159
|
+
*/
|
|
160
|
+
detach?: boolean | undefined;
|
|
161
|
+
/**
|
|
162
|
+
* What the person sent, recorded as the run's first event in `runs`, so a re-attached browser shows it. Pass the
|
|
163
|
+
* `promptId` useClaudeAgent sends as `id`: a browser that re-attaches with `initialEvents` then replaces the run's
|
|
164
|
+
* events instead of adding them again.
|
|
165
|
+
*/
|
|
166
|
+
prompt?: {
|
|
167
|
+
id: string;
|
|
168
|
+
text: string;
|
|
169
|
+
references?: EntityRef[] | undefined;
|
|
170
|
+
} | undefined;
|
|
171
|
+
/** Which tools' input a person may edit before allowing it. Every tool by default. See claudeCanUseTool. */
|
|
172
|
+
editable?: ClaudeCanUseToolOptions["editable"] | undefined;
|
|
173
|
+
/** Close a permission request nobody answered after this long, as expired (denied). No limit by default; set one with `detach`. */
|
|
174
|
+
approvalTimeoutMs?: number | undefined;
|
|
175
|
+
/** The permission modes setClaudeAgentPermissionMode may switch this run to. Any mode by default. */
|
|
176
|
+
modes?: ModePolicy | undefined;
|
|
27
177
|
};
|
|
28
178
|
/**
|
|
29
179
|
* Run an agent and stream it to useClaudeAgent.
|
|
@@ -38,16 +188,51 @@ export type StreamClaudeAgentOptions = {
|
|
|
38
188
|
* )
|
|
39
189
|
* }
|
|
40
190
|
*/
|
|
41
|
-
export declare function streamClaudeAgent(run: RunClaudeAgent, { signal, owner, describeError, onMessage }?: StreamClaudeAgentOptions): Response;
|
|
191
|
+
export declare function streamClaudeAgent(run: RunClaudeAgent, { signal, owner, describeError, onMessage, onEvent, approvals, runs, runId, detach, prompt, editable, approvalTimeoutMs, modes }?: StreamClaudeAgentOptions): Response;
|
|
42
192
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
193
|
+
* Stream a run's events again, from index `from`, then live until it ends: for a browser re-attaching after a
|
|
194
|
+
* reload. 404 when the store doesn't know the run, 403 when `owner` isn't who started it.
|
|
195
|
+
*
|
|
196
|
+
* // app/api/agent/[runId]/route.ts
|
|
197
|
+
* export async function GET(request: Request, { params }) {
|
|
198
|
+
* const from = Number(new URL(request.url).searchParams.get("from") ?? 0)
|
|
199
|
+
* return attachClaudeAgentRun(runs, (await params).runId, { from, owner: userId, signal: request.signal })
|
|
200
|
+
* }
|
|
201
|
+
*/
|
|
202
|
+
export declare function attachClaudeAgentRun(runs: ClaudeRunStore, runId: string, { from, owner, signal, pollMs }?: {
|
|
203
|
+
from?: number | undefined;
|
|
204
|
+
owner?: string | undefined;
|
|
205
|
+
signal?: AbortSignal | undefined;
|
|
206
|
+
pollMs?: number | undefined;
|
|
207
|
+
}): Promise<Response>;
|
|
208
|
+
/** Stop a run this process is running. False when it isn't running here, or `owner` didn't start it. */
|
|
209
|
+
export declare function stopClaudeAgentRun(runId: string, owner?: string): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Change a running agent's permission mode (the SDK's `setPermissionMode`), and tell the browser. Only for a query
|
|
212
|
+
* in streaming input mode, as the SDK requires. False when the run isn't here, `owner` didn't start it, the mode
|
|
213
|
+
* isn't allowed, or the SDK refused. The route is where policy is enforced: a mode PermissionMode shows as locked
|
|
214
|
+
* must be left out of `allowed` (or the run's `modes`) too, since anyone can post to the route directly.
|
|
215
|
+
*/
|
|
216
|
+
export declare function setClaudeAgentPermissionMode(runId: string, mode: PermissionMode, owner?: string, { allowed }?: {
|
|
217
|
+
allowed?: ModePolicy | undefined;
|
|
218
|
+
}): Promise<boolean>;
|
|
219
|
+
/**
|
|
220
|
+
* Check an answer from the browser against the request it answers, and record it. False when there's no such
|
|
221
|
+
* request, it's already settled, `owner` isn't the run's owner, or the answer doesn't fit the request (an edited
|
|
222
|
+
* input that isn't an object, answers to a request that isn't a question, a suggestion that wasn't offered).
|
|
46
223
|
*
|
|
47
224
|
* // app/api/agent/approve/route.ts
|
|
48
225
|
* export async function POST(request: Request) {
|
|
49
|
-
* const { id,
|
|
50
|
-
* return Response.json({ ok:
|
|
226
|
+
* const { id, ...answer } = await request.json()
|
|
227
|
+
* return Response.json({ ok: await answerClaudeApproval(approvals, id, answer, { owner: userId }) })
|
|
51
228
|
* }
|
|
52
229
|
*/
|
|
230
|
+
export declare function answerClaudeApproval(approvals: ApprovalStore, id: string, answer: ClaudeApprovalAnswer, { owner }?: {
|
|
231
|
+
owner?: string | undefined;
|
|
232
|
+
}): Promise<boolean>;
|
|
233
|
+
/**
|
|
234
|
+
* Answer a waiting permission request in the default, in-memory store. Kept from 1.4; answerClaudeApproval takes a
|
|
235
|
+
* store and the full answer (an edited input, answers to questions, "always allow"). Returns false when there's no
|
|
236
|
+
* such request, or `owner` doesn't match the run's owner.
|
|
237
|
+
*/
|
|
53
238
|
export declare function answerClaudeAgentApproval(id: string, approved: boolean, reason?: string, owner?: string): boolean;
|