@primusclaw/personal-agent 0.4.0 → 0.5.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/index.js +945 -741
- package/dist/types/approvals/questions.d.ts +7 -0
- package/dist/types/approvals/records.d.ts +2 -2
- package/dist/types/approvals/views.d.ts +8 -0
- package/dist/types/assistant/receipts.d.ts +1 -1
- package/dist/types/locales/approval.d.ts +11 -0
- package/dist/types/locales/turn.d.ts +2 -0
- package/dist/types/ports/store/approvals.d.ts +24 -2
- package/dist/types/ports/surface.d.ts +5 -2
- package/dist/types/routing/credentials.d.ts +9 -1
- package/dist/types/routing/deps.d.ts +1 -1
- package/dist/types/routing/personal-text.d.ts +1 -1
- package/dist/types/routing/question-reply.d.ts +22 -0
- package/dist/types/routing/turn-start.d.ts +19 -0
- package/dist/types/turn/engine/context.d.ts +4 -2
- package/dist/types/turn/engine/run-turn.d.ts +2 -0
- package/dist/types/turn/progress/status-message.d.ts +20 -0
- package/dist/types/turn/runner.d.ts +2 -2
- package/package.json +1 -1
|
@@ -34,3 +34,10 @@ export interface Answers {
|
|
|
34
34
|
* typed; a choice the card never offered is ignored.
|
|
35
35
|
*/
|
|
36
36
|
export declare function answersOf(data: Readonly<Record<string, unknown>>): Answers;
|
|
37
|
+
/**
|
|
38
|
+
* A message the person typed in the chat while a question card waited, taken as the card's answer. With one question, a
|
|
39
|
+
* reply that names its options (by label or by number, several of them for a multiple choice) answers with their labels,
|
|
40
|
+
* as a press on the card would; any other reply is the free answer the card's text box takes. With several questions the
|
|
41
|
+
* whole reply answers each of them: the agent reads which part answers which. Nothing is skipped.
|
|
42
|
+
*/
|
|
43
|
+
export declare function typedAnswers(questions: readonly CardQuestion[], typed: string): Answers;
|
|
@@ -35,8 +35,8 @@ export declare const TURN_DEADLINE_SECONDS: number;
|
|
|
35
35
|
* the person the turn is for (Python `store.save_approval(sender.aad_id, ...)`).
|
|
36
36
|
*/
|
|
37
37
|
export interface TurnApprovalRecords {
|
|
38
|
-
record(userId: string, sessionId: string, toolUseId: string, tool: string, expiresIn: number | undefined, envelope: Envelope): boolean;
|
|
39
|
-
sent(sessionId: string, toolUseId: string): void;
|
|
38
|
+
record(userId: string, sessionId: string, toolUseId: string, tool: string, expiresIn: number | undefined, envelope: Envelope, questions?: unknown): boolean;
|
|
39
|
+
sent(sessionId: string, toolUseId: string, cardId?: string): void;
|
|
40
40
|
unsent(sessionId: string, toolUseId: string): void;
|
|
41
41
|
}
|
|
42
42
|
/** The records of the approvals a turn shows (the Python `on_approval`, `on_approval_sent`, `on_approval_unsent`). */
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* channel adapter renders them; `approvalView` (approval-view.ts) is what an approval card says.
|
|
4
4
|
*/
|
|
5
5
|
import type { JsonObject } from "../json.js";
|
|
6
|
+
import type { Lang } from "../locales/lang.js";
|
|
6
7
|
import type { CardQuestion } from "./questions.js";
|
|
7
8
|
/** An approval card: the arguments of the Python worker's `render.permission_card`, one for one. */
|
|
8
9
|
export interface ApprovalCardModel {
|
|
@@ -27,6 +28,11 @@ export interface QuestionCardModel {
|
|
|
27
28
|
readonly ownerName: string;
|
|
28
29
|
/** A line under the header: which task asks, or what happened when the card comes back after a click ("" when none). */
|
|
29
30
|
readonly note: string;
|
|
31
|
+
/**
|
|
32
|
+
* The card says it can also be answered by a message in the chat: a turn's question, which a typed message answers
|
|
33
|
+
* (`routing/question-reply.ts`). A work item's question is answered on its card only.
|
|
34
|
+
*/
|
|
35
|
+
readonly typedReply?: boolean;
|
|
30
36
|
}
|
|
31
37
|
/** What replaces an approval card once it was answered (render.decided_card). */
|
|
32
38
|
export interface ApprovalDecidedModel {
|
|
@@ -47,6 +53,8 @@ export interface QuestionAnsweredModel {
|
|
|
47
53
|
readonly answers: readonly (readonly [string, string])[];
|
|
48
54
|
readonly when: number;
|
|
49
55
|
readonly zone: string;
|
|
56
|
+
/** Answered by a message typed in the chat (not on the card), in this language: the card says "Answered: <answer>". */
|
|
57
|
+
readonly replied?: Lang;
|
|
50
58
|
}
|
|
51
59
|
/** An approval card put back after a press that did not go through: the note, then Approve and Deny again. */
|
|
52
60
|
export interface ApprovalAgainModel {
|
|
@@ -62,7 +62,7 @@ export declare class ReceiptConversation implements Conversation {
|
|
|
62
62
|
update(id: MessageId, message: OutMessage, options?: UpdateOptions): Promise<void>;
|
|
63
63
|
delete(id: MessageId): ReturnType<Conversation["delete"]>;
|
|
64
64
|
outgoing(message: OutMessage): Envelope;
|
|
65
|
-
deliver(envelope: Envelope): Promise<
|
|
65
|
+
deliver(envelope: Envelope): Promise<MessageId | undefined>;
|
|
66
66
|
openStream(replyTo: MessageId, status: string): ReturnType<Conversation["openStream"]>;
|
|
67
67
|
/** What the assistant said beside the handoff, when no text message carried it: said on its own. */
|
|
68
68
|
sayPostscript(): Promise<void>;
|
|
@@ -28,4 +28,15 @@ export declare const approvalText: import("./catalog.js").Catalog<{
|
|
|
28
28
|
}) => string;
|
|
29
29
|
questionAsker: string;
|
|
30
30
|
send: string;
|
|
31
|
+
/** Under a question card's questions: a client that does not show the card can still answer. */
|
|
32
|
+
questionReply: string;
|
|
33
|
+
/** The same in a group chat, where only a message that @mentions the bot reaches it. */
|
|
34
|
+
questionReplyGroup: string;
|
|
35
|
+
/** A question card once a message typed in the chat answered it. */
|
|
36
|
+
questionReplied: (p: {
|
|
37
|
+
answer: string;
|
|
38
|
+
}) => string;
|
|
39
|
+
questionRepliedAt: (p: {
|
|
40
|
+
at: string;
|
|
41
|
+
}) => string;
|
|
31
42
|
}>;
|
|
@@ -21,6 +21,8 @@ export declare const turnText: import("./catalog.js").Catalog<{
|
|
|
21
21
|
thinking: string;
|
|
22
22
|
/** A turn still running when its stream has to close: the answer follows as a message of its own. */
|
|
23
23
|
stillWorking: string;
|
|
24
|
+
/** A turn whose stream is closed because a card now waits for the person's choice. */
|
|
25
|
+
awaitingChoice: string;
|
|
24
26
|
interrupted: string;
|
|
25
27
|
/** What a turn the person stopped ends with. */
|
|
26
28
|
stopped: string;
|
|
@@ -25,12 +25,29 @@ export interface NewApproval {
|
|
|
25
25
|
readonly expiresAt: number;
|
|
26
26
|
/** The card as it will be published, kept until `approvalSent` so a worker that dies before the send leaves it to the next. */
|
|
27
27
|
readonly envelope?: JsonObject | null;
|
|
28
|
+
/**
|
|
29
|
+
* A question card of a turn: its questions as the card's button carries them. Kept so that what the person types next in
|
|
30
|
+
* the chat can be taken as the answer (`pendingQuestion`).
|
|
31
|
+
*/
|
|
32
|
+
readonly questions?: readonly JsonObject[] | null;
|
|
33
|
+
}
|
|
34
|
+
/** A question card still waiting for its answer, with what it takes to answer it from a typed message. */
|
|
35
|
+
export interface PendingQuestion {
|
|
36
|
+
readonly sessionId: string;
|
|
37
|
+
readonly toolUseId: string;
|
|
38
|
+
readonly userId: string;
|
|
39
|
+
/** When it runs out, epoch seconds. */
|
|
40
|
+
readonly expiresAt: number;
|
|
41
|
+
/** The questions as recorded with the card (`NewApproval.questions`). */
|
|
42
|
+
readonly questions: readonly JsonObject[];
|
|
43
|
+
/** The chat's id of the card ("" when the channel never said it: the card cannot be edited). */
|
|
44
|
+
readonly cardId: string;
|
|
28
45
|
}
|
|
29
46
|
export interface ApprovalRepository {
|
|
30
47
|
/** True when this call recorded it; false when a card for the same approval was recorded before. */
|
|
31
48
|
saveApproval(approval: NewApproval): boolean;
|
|
32
|
-
/** The card reached the chat: nothing is left to send. */
|
|
33
|
-
approvalSent(sessionId: string, toolUseId: string): void;
|
|
49
|
+
/** The card reached the chat: nothing is left to send. `cardId`: the chat's id of the card, when it said it. */
|
|
50
|
+
approvalSent(sessionId: string, toolUseId: string, cardId?: string): void;
|
|
34
51
|
/** Its card is being sent right now by this process and may still fail. */
|
|
35
52
|
approvalInFlight(sessionId: string, toolUseId: string): boolean;
|
|
36
53
|
/** The card never reached the chat: take the record back (a row answered meanwhile stays). */
|
|
@@ -40,6 +57,11 @@ export interface ApprovalRepository {
|
|
|
40
57
|
/** A claimed card could not be sent: the next sweep tries again. */
|
|
41
58
|
approvalSendFailed(sessionId: string, toolUseId: string): void;
|
|
42
59
|
getApproval(sessionId: string, toolUseId: string): Approval | null;
|
|
60
|
+
/**
|
|
61
|
+
* The newest question card of `userId` in `sessionId` that is still pending, in time, and was recorded with its questions;
|
|
62
|
+
* null when there is none.
|
|
63
|
+
*/
|
|
64
|
+
pendingQuestion(sessionId: string, userId: string): PendingQuestion | null;
|
|
43
65
|
/** Move an approval to `state`; true if this call did it (only from 'pending' unless `onlyIfPending` is false). */
|
|
44
66
|
closeApproval(sessionId: string, toolUseId: string, state: ApprovalState, options?: {
|
|
45
67
|
readonly onlyIfPending?: boolean;
|
|
@@ -336,8 +336,11 @@ export interface Conversation {
|
|
|
336
336
|
delete(id: MessageId): Promise<Result<void, DeleteUnsupported>>;
|
|
337
337
|
/** The envelope `send` would publish for `message` (masked in a group), built without sending it. */
|
|
338
338
|
outgoing(message: OutMessage): Envelope;
|
|
339
|
-
/**
|
|
340
|
-
|
|
339
|
+
/**
|
|
340
|
+
* Publish an envelope `outgoing` built (possibly in another process, from storage). The id of the posted message when the
|
|
341
|
+
* channel said it at once (a direct send); undefined otherwise (a queued send: the message cannot be edited by id).
|
|
342
|
+
*/
|
|
343
|
+
deliver(envelope: Envelope): Promise<MessageId | undefined>;
|
|
341
344
|
/**
|
|
342
345
|
* A live stream that answers `replyTo` (the person's message), showing `status` as its first informative update.
|
|
343
346
|
* Success means that first update has been sent and the channel took it; refused when the channel cannot stream here
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { LinkRepository } from "../ports/store/link.js";
|
|
2
|
+
import type { OutMessage, UserRef } from "../ports/surface.js";
|
|
3
|
+
import type { TokenExchange } from "../plugins/token-exchange.js";
|
|
2
4
|
import type { Chat } from "./chat.js";
|
|
3
5
|
import type { RouterDeps } from "./deps.js";
|
|
4
6
|
import type { CredentialProvider } from "./features.js";
|
|
@@ -12,6 +14,12 @@ export declare const IDENTITY_CARD_INTERVAL_SECONDS: number;
|
|
|
12
14
|
/** Its kind in the store's notice record (`claimGithubNotice`): the time it was last sent to the person. */
|
|
13
15
|
export declare const IDENTITY_CARD_NOTICE = "identity_card";
|
|
14
16
|
type CredentialDeps = Pick<RouterDeps, "store" | "exchange" | "config" | "logger">;
|
|
17
|
+
/**
|
|
18
|
+
* What an action of the person's outside a turn (a thumb on an answer) calls Claw with: what their chats run on, so it acts
|
|
19
|
+
* on the same session as the same Claw user. With chats on the exchange (`exchange` given), the person's exchanged token,
|
|
20
|
+
* else their linked key; without, the linked key. Undefined when they have neither. Never asks or tells them anything.
|
|
21
|
+
*/
|
|
22
|
+
export declare function chatCredentialOf(links: Pick<LinkRepository, "getKey">, exchange: TokenExchange | undefined): (sender: UserRef) => Promise<string | undefined>;
|
|
15
23
|
/**
|
|
16
24
|
* What Claw is called with for a person, and what a person who has none is told (the Python `Agent._credential`,
|
|
17
25
|
* `_unlinked`, `_connect_identity`, `_binding_card`, `_ask_to_link`, `_background_credential`, `_fresh_credential`).
|
|
@@ -38,7 +38,7 @@ export interface RouterConfig {
|
|
|
38
38
|
readonly ownThumbsMobile: boolean;
|
|
39
39
|
}
|
|
40
40
|
/** The repositories the router reads and writes (the W1 store, as far as routing goes). */
|
|
41
|
-
export type RouterStore = Pick<StorePort, "links" | "references" | "prefs" | "members" | "sessions" | "repoHistory" | "turns" | "onboarding" | "idempotency" | "assistantMessages" | "notifySubs" | "reviewDelegation" | "now">;
|
|
41
|
+
export type RouterStore = Pick<StorePort, "links" | "references" | "prefs" | "members" | "sessions" | "repoHistory" | "turns" | "onboarding" | "idempotency" | "assistantMessages" | "notifySubs" | "reviewDelegation" | "approvals" | "now">;
|
|
42
42
|
/** The per-person limits (Python `limits.py`): messages per window and tasks at the same time. */
|
|
43
43
|
export interface RouterLimits {
|
|
44
44
|
readonly maxConcurrentTasks: number;
|
|
@@ -2,7 +2,7 @@ import type { InboundFile, InboundMessage } from "../ports/surface.js";
|
|
|
2
2
|
import type { Chat } from "./chat.js";
|
|
3
3
|
import type { CommandTable } from "./command-table.js";
|
|
4
4
|
import type { RouterContext } from "./context.js";
|
|
5
|
-
import type
|
|
5
|
+
import { type TurnStarter } from "./turn-start.js";
|
|
6
6
|
/**
|
|
7
7
|
* A 1:1 message that is not one of the chat's commands, as it goes on (the Python `Agent._text_of`, `_on_text`,
|
|
8
8
|
* `_sent_on`, `_talks_to_agent`, `_session_control`, `_understand`, `_understood`, `_offer_github`, `_attachments`):
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Chat } from "./chat.js";
|
|
2
|
+
import type { RouterContext } from "./context.js";
|
|
3
|
+
/**
|
|
4
|
+
* A question with less than this left of its wait is not answered from a typed message: Brain may already have stopped
|
|
5
|
+
* waiting (the card's time is counted from when the worker saw the question, a little after Brain's), and an answer nobody
|
|
6
|
+
* waits for is dropped. The message then goes on as a new one, as before.
|
|
7
|
+
*/
|
|
8
|
+
export declare const TYPED_ANSWER_MARGIN_SECONDS = 15;
|
|
9
|
+
/** A typed message that may answer the person's waiting question. */
|
|
10
|
+
export interface TypedReply {
|
|
11
|
+
readonly chat: Chat;
|
|
12
|
+
readonly text: string;
|
|
13
|
+
/** The Claw credential of the person, read when there is a question to answer. */
|
|
14
|
+
readonly credential: () => Promise<string>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Answers the question card that waits in the chat's session with `reply.text`: true when it did (the card now says
|
|
18
|
+
* "Answered: ...", and the message must not go on as a new one); false when there was nothing to answer, or it could not be
|
|
19
|
+
* answered (the message then goes on as before). Only the person the card was raised for answers it: their own session in
|
|
20
|
+
* this chat, their own record.
|
|
21
|
+
*/
|
|
22
|
+
export declare function answerWaitingQuestion(ctx: RouterContext, reply: TypedReply): Promise<boolean>;
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import type { Lang } from "../locales/lang.js";
|
|
2
|
+
import type { Logger } from "../ports/logger.js";
|
|
2
3
|
import type { InboundFile } from "../ports/surface.js";
|
|
3
4
|
import type { Chat } from "./chat.js";
|
|
4
5
|
import type { RouterContext } from "./context.js";
|
|
5
6
|
import type { ReviewRunFields, TurnOutcome } from "./turn-runner.js";
|
|
6
7
|
/** Teams on a phone or a tablet: its own Stop under a reply is greyed out, and its own thumbs never reach the worker. */
|
|
7
8
|
export declare function isMobile(clientPlatform: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* The path a message from Teams took: to the person's assistant, to a plain Claw session of their own (the old path, neither
|
|
11
|
+
* the assistant's nor a work item's), or to a review's turn. Logged so the worker's lines can be counted per path.
|
|
12
|
+
*/
|
|
13
|
+
export type TurnRoute = "assistant" | "legacy" | "review";
|
|
14
|
+
/**
|
|
15
|
+
* The line for a turn started from Teams: where it came from and which path it took, never its words or any id. One line
|
|
16
|
+
* per turn: a message to the assistant or to a plain session is one turn, and a review request for several pull requests
|
|
17
|
+
* starts one review turn (and one line) for each.
|
|
18
|
+
*/
|
|
19
|
+
export declare function logTurnStarted(logger: Logger, clientPlatform: string, group: boolean, route: TurnRoute): void;
|
|
8
20
|
/** A review the review service starts as a turn here (its item runs in Claw already; the turn only follows it). */
|
|
9
21
|
export interface ReviewTurnStart {
|
|
10
22
|
/** The work item Claw made for it ("" none: the turn makes a session of its own). */
|
|
@@ -41,6 +53,11 @@ export interface StartTurn {
|
|
|
41
53
|
readonly sent?: string;
|
|
42
54
|
readonly files?: readonly InboundFile[];
|
|
43
55
|
readonly review?: ReviewTurnStart;
|
|
56
|
+
/**
|
|
57
|
+
* The person typed it in the chat (not a button, not a review): while the agent waits on a question card in this chat's
|
|
58
|
+
* session, it is the answer to that question and starts no turn.
|
|
59
|
+
*/
|
|
60
|
+
readonly typed?: boolean;
|
|
44
61
|
}
|
|
45
62
|
/**
|
|
46
63
|
* Starting and following a turn (the Python `Agent._start_turn`, `_queue_behind`, `_guarded`, `_record_session`,
|
|
@@ -56,6 +73,8 @@ export declare class TurnStarter {
|
|
|
56
73
|
settled(): Promise<void>;
|
|
57
74
|
/** The turn that runs (its end is `done`), or undefined when none was started (the person was told why). */
|
|
58
75
|
start(request: StartTurn): Promise<RunningTurn | undefined>;
|
|
76
|
+
/** A typed message the waiting question card of the chat's session took as its answer (`question-reply.ts`). */
|
|
77
|
+
private answersQuestion;
|
|
59
78
|
private track;
|
|
60
79
|
/** The turn goes to Claw now; its end is `done`. */
|
|
61
80
|
private launch;
|
|
@@ -70,9 +70,11 @@ export interface TurnHooks {
|
|
|
70
70
|
/**
|
|
71
71
|
* An approval or question is about to be shown, as `envelope`: false when a card for it is already in a chat (the
|
|
72
72
|
* notification got there first), and the turn then shows none. `expiresIn`: the seconds Brain waits for the answer.
|
|
73
|
+
* `questions`: a question's questions, as its event carried them (undefined for an approval).
|
|
73
74
|
*/
|
|
74
|
-
readonly onApproval?: (sessionId: string, toolUseId: string, tool: string, expiresIn: number | undefined, envelope: Envelope) => boolean | undefined;
|
|
75
|
-
|
|
75
|
+
readonly onApproval?: (sessionId: string, toolUseId: string, tool: string, expiresIn: number | undefined, envelope: Envelope, questions?: unknown) => boolean | undefined;
|
|
76
|
+
/** The card is in the chat; `cardId`: the chat's id of it, when the chat said it. */
|
|
77
|
+
readonly onApprovalSent?: (sessionId: string, toolUseId: string, cardId?: string) => void;
|
|
76
78
|
readonly onApprovalUnsent?: (sessionId: string, toolUseId: string) => void;
|
|
77
79
|
/** (session, "started" | "delivered" | "failed", Claw message id or ''). */
|
|
78
80
|
readonly onTurn?: (sessionId: string, what: "started" | "delivered" | "failed", messageId: string) => void;
|
|
@@ -18,5 +18,7 @@ export interface TurnControls {
|
|
|
18
18
|
/** The turn is cancelled: no live edit is sent after it, and the run's record is still kept. */
|
|
19
19
|
readonly signal?: AbortSignal;
|
|
20
20
|
}
|
|
21
|
+
/** The id Claw gives a message it queued behind a running turn (`queuedMessageId`, claw/packages/api/src/tasks/chat-run.ts). */
|
|
22
|
+
export declare const QUEUED_MESSAGE_PREFIX = "claw-pending-";
|
|
21
23
|
/** Runs the turn and always leaves the user a message; `controls.onSession` records the session id. */
|
|
22
24
|
export declare function runTurn(ctx: TurnContext, controls: TurnControls): Promise<void>;
|
|
@@ -54,6 +54,8 @@ export declare class StatusMessage<S> {
|
|
|
54
54
|
private opening;
|
|
55
55
|
private expiry;
|
|
56
56
|
private again;
|
|
57
|
+
/** The stream being closed because a card waits for the person (`awaitingChoice`). */
|
|
58
|
+
private choice;
|
|
57
59
|
private preparingTimer;
|
|
58
60
|
private lastText;
|
|
59
61
|
private lastAt;
|
|
@@ -80,6 +82,24 @@ export declare class StatusMessage<S> {
|
|
|
80
82
|
private statusLines;
|
|
81
83
|
/** Close the stream with STILL_WORKING before the chat's limit; the answer, whenever it comes, is a message of its own. */
|
|
82
84
|
private closeInTime;
|
|
85
|
+
/**
|
|
86
|
+
* Close the open stream with `line` (after the agent's words in the bubble) while the turn goes on; the answer, whenever it comes, is
|
|
87
|
+
* a message of its own. Nothing more is sent to the stream once this has begun.
|
|
88
|
+
*/
|
|
89
|
+
private closeEarly;
|
|
90
|
+
/**
|
|
91
|
+
* A card now waits for the person (a question of the agent): it is their turn, so the floating status must not go on
|
|
92
|
+
* saying "Thinking…" until the chat's limit. An open stream is closed at once with AWAITING_CHOICE, and the answer comes
|
|
93
|
+
* as a message of its own, as after the limit. Without a stream (the progress message) nothing changes: it has no
|
|
94
|
+
* spinner. Never fails the turn.
|
|
95
|
+
*/
|
|
96
|
+
awaitingChoice(): void;
|
|
97
|
+
/**
|
|
98
|
+
* Claw queued the message behind a turn it is still running: `notice` closes the stream at once, so it does not say
|
|
99
|
+
* "Thinking…" for the whole wait. The answer comes as a message of its own, as after the limit. When the stream did not open
|
|
100
|
+
* after all, `notice` is said as a message. False when there is no stream: the caller says it. Never fails the turn.
|
|
101
|
+
*/
|
|
102
|
+
queued(notice: string): boolean;
|
|
83
103
|
/** The chat's id of the posted message; undefined when the post failed or its id never came (nothing is edited then). */
|
|
84
104
|
private messageId;
|
|
85
105
|
/**
|
|
@@ -24,8 +24,8 @@ export interface TurnApprovals {
|
|
|
24
24
|
* False when a card for this approval is already in a chat: the turn then shows none. `userId`: the person the turn is for,
|
|
25
25
|
* whose approval it is (Python `store.save_approval(sender.aad_id, ...)`).
|
|
26
26
|
*/
|
|
27
|
-
record(userId: string, sessionId: string, toolUseId: string, tool: string, expiresIn: number | undefined, envelope: Envelope): boolean;
|
|
28
|
-
sent(sessionId: string, toolUseId: string): void;
|
|
27
|
+
record(userId: string, sessionId: string, toolUseId: string, tool: string, expiresIn: number | undefined, envelope: Envelope, questions?: unknown): boolean;
|
|
28
|
+
sent(sessionId: string, toolUseId: string, cardId?: string): void;
|
|
29
29
|
unsent(sessionId: string, toolUseId: string): void;
|
|
30
30
|
}
|
|
31
31
|
/** What a review turn adds to a chat turn (the review service fills it in). */
|