@object-ui/plugin-chatbot 17.5.0 → 17.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/CHANGELOG.md +2416 -0
- package/README.md +37 -12
- package/dist/AiPendingActionsInbox.d.ts +8 -2
- package/dist/AiPendingActionsInbox.d.ts.map +1 -1
- package/dist/ChatbotEnhanced.d.ts +122 -48
- package/dist/ChatbotEnhanced.d.ts.map +1 -1
- package/dist/FloatingChatbot.d.ts +1 -1
- package/dist/FloatingChatbot.d.ts.map +1 -1
- package/dist/chatMessageAdapter.d.ts +18 -6
- package/dist/chatMessageAdapter.d.ts.map +1 -1
- package/dist/elements/index.d.ts +10 -10
- package/dist/elements/prompt-input.d.ts +1 -1
- package/dist/elements/prompt-input.d.ts.map +1 -1
- package/dist/elements/tool.d.ts +13 -1
- package/dist/elements/tool.d.ts.map +1 -1
- package/dist/index.d.ts +35 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2180 -1794
- package/dist/index.umd.cjs +4 -2
- package/dist/mapMessages.d.ts +148 -4
- package/dist/mapMessages.d.ts.map +1 -1
- package/dist/tool-display.d.ts +97 -26
- package/dist/tool-display.d.ts.map +1 -1
- package/dist/useAiApprovalsTranslation.d.ts +76 -0
- package/dist/useAiApprovalsTranslation.d.ts.map +1 -0
- package/dist/useAiModels.d.ts +1 -1
- package/dist/useHitlInChat.d.ts +2 -2
- package/dist/useObjectChat.d.ts +94 -18
- package/dist/useObjectChat.d.ts.map +1 -1
- package/package.json +13 -17
package/dist/mapMessages.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ChatMessage, ChatToolInvocation, ChatBuildProgress } from './ChatbotEnhanced';
|
|
1
|
+
import { ChatMessage, ChatToolInvocation, ChatBuildProgress } from './ChatbotEnhanced.js';
|
|
2
2
|
interface AnyPart {
|
|
3
3
|
type?: string;
|
|
4
4
|
text?: string;
|
|
@@ -10,7 +10,29 @@ interface AnyPart {
|
|
|
10
10
|
args?: unknown;
|
|
11
11
|
result?: unknown;
|
|
12
12
|
errorText?: string;
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Free-form on purpose. `AnyPart` absorbs whatever a producer hands the
|
|
15
|
+
* mapper, and `state` is NOT one namespace: a tool part carries the
|
|
16
|
+
* tool-invocation lifecycle, while `@ai-sdk/react`'s text and reasoning
|
|
17
|
+
* parts carry `'streaming' | 'done'`. Typing this member against the
|
|
18
|
+
* OUTPUT contract made the deliberately-permissive input interface
|
|
19
|
+
* stricter than the union it exists to absorb, so the SDK's own
|
|
20
|
+
* `UIMessage[]` — the documented input of the exported mappers — was
|
|
21
|
+
* refused outright (objectui#8214). `isToolState` below is what keeps the
|
|
22
|
+
* output checked; this stays open.
|
|
23
|
+
*/
|
|
24
|
+
state?: string;
|
|
25
|
+
/**
|
|
26
|
+
* The chat runtime's approval envelope, as it arrives on a tool part.
|
|
27
|
+
*
|
|
28
|
+
* `unknown`, like every other absorbing member here, and deliberately NOT
|
|
29
|
+
* the envelope's declared shape: this interface exists to take whatever a
|
|
30
|
+
* producer hands the mapper, and the one time a member was typed against the
|
|
31
|
+
* OUTPUT contract it made the permissive input interface stricter than the
|
|
32
|
+
* union it absorbs (objectui#8214, the `state` member). {@link liftApproval}
|
|
33
|
+
* is what keeps the OUTPUT checked; this stays open.
|
|
34
|
+
*/
|
|
35
|
+
approval?: unknown;
|
|
14
36
|
url?: string;
|
|
15
37
|
href?: string;
|
|
16
38
|
title?: string;
|
|
@@ -45,13 +67,29 @@ interface AnyUIMessage {
|
|
|
45
67
|
* still-pending proposal as "Completed" (#787 finding B / #2362).
|
|
46
68
|
*/
|
|
47
69
|
export declare function parseResultEnvelope(result: unknown): Record<string, unknown> | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* The ObjectStack HITL envelope a tool result carries when the framework's
|
|
72
|
+
* `action-tools.ts` proposes a destructive action:
|
|
73
|
+
* `{ status: 'pending_approval', pendingActionId: 'pa_…', … }`.
|
|
74
|
+
*
|
|
75
|
+
* Exported (objectui#8442) so the app-shell's HYDRATION mapper derives the id
|
|
76
|
+
* from the same parse the live mapper uses. The id is never persisted as a part
|
|
77
|
+
* key — it exists in rehydrated history only inside this envelope — so a second
|
|
78
|
+
* hand-rolled reader there would be a second dialect of one contract, which is
|
|
79
|
+
* exactly what AGENTS.md Commandment #0.1 refuses.
|
|
80
|
+
*/
|
|
81
|
+
export declare function detectPendingApproval(result: unknown): {
|
|
82
|
+
pendingActionId: string;
|
|
83
|
+
raw: Record<string, unknown>;
|
|
84
|
+
} | undefined;
|
|
48
85
|
/**
|
|
49
86
|
* Best-effort detector for the framework's ADR-0033 draft envelopes. Metadata
|
|
50
87
|
* authoring tools stage changes as DRAFTS and return one of:
|
|
51
88
|
* • single — `{ status:'drafted', type, name, summary, changedKeys }`
|
|
52
89
|
* (create_object / add_field / create_metadata / update_metadata / …)
|
|
53
90
|
* • batch — `{ status:'drafted', drafted:[{type,name}], failed, summary }`
|
|
54
|
-
* (apply_blueprint)
|
|
91
|
+
* (apply_blueprint), or the same batch with `kind:'edit'` (apply_edit,
|
|
92
|
+
* an INCREMENTAL edit — objectui#10109)
|
|
55
93
|
* We lift the reviewable `{ type, name }` targets so the chat can render a
|
|
56
94
|
* "Review N change(s)" affordance that opens the designer's review/diff.
|
|
57
95
|
* `blueprint_proposed` (propose_blueprint) has no draft yet → not surfaced here.
|
|
@@ -63,9 +101,25 @@ export interface DraftReview {
|
|
|
63
101
|
}>;
|
|
64
102
|
summary?: string;
|
|
65
103
|
packageId?: string;
|
|
104
|
+
/**
|
|
105
|
+
* Backend lifecycle intent (from the tool result). `true` for whole-app
|
|
106
|
+
* builds (apply_blueprint) — eligible for the auto-publish "magic moment".
|
|
107
|
+
* Omitted for incremental edits, which stay drafts for explicit review.
|
|
108
|
+
*/
|
|
66
109
|
autoPublishable?: boolean;
|
|
110
|
+
/** Count of artifacts that failed in a partial build, surfaced not hidden. */
|
|
67
111
|
failedCount?: number;
|
|
112
|
+
/**
|
|
113
|
+
* ADR-0045: the build was MATERIALIZED in-turn — real tables and seed
|
|
114
|
+
* rows exist; the app is live but `hidden` (unlisted). Preview should
|
|
115
|
+
* open the REAL app URL, not the draft overlay.
|
|
116
|
+
*/
|
|
68
117
|
materialized?: boolean;
|
|
118
|
+
/**
|
|
119
|
+
* ADR-0038 L1 graph-lint verdict for the staged build. Rendered as a
|
|
120
|
+
* verified/issues chip so "drafted" and "verified" read as the two
|
|
121
|
+
* separate statements they are. Absent on older tool output.
|
|
122
|
+
*/
|
|
69
123
|
verification?: {
|
|
70
124
|
errors: number;
|
|
71
125
|
warnings: number;
|
|
@@ -90,6 +144,18 @@ export interface DraftReview {
|
|
|
90
144
|
* status panel, never asserted as done).
|
|
91
145
|
*/
|
|
92
146
|
nextSteps?: string[];
|
|
147
|
+
/**
|
|
148
|
+
* objectui#10109 — the producer's marker for an INCREMENTAL edit, lifted
|
|
149
|
+
* from the envelope's own `kind`: `apply_edit` answers `kind: 'edit'`, and a
|
|
150
|
+
* whole-app `apply_blueprint` build carries no `kind`. An edit's `items` may
|
|
151
|
+
* honestly include the `app` artifact it re-staged (an `add_object` op
|
|
152
|
+
* merges the nav), so the readers that infer a whole-app build from a draft
|
|
153
|
+
* review's staged artifact types check this first: `buildProgressFromDraftReview`
|
|
154
|
+
* here, and app-shell's built-moment transition (`detectBuiltAppPackage` reads
|
|
155
|
+
* the envelope's own `kind` instead). Only the value those readers act on is
|
|
156
|
+
* declared: an envelope that does not say `'edit'` lifts nothing here.
|
|
157
|
+
*/
|
|
158
|
+
kind?: 'edit';
|
|
93
159
|
}
|
|
94
160
|
/**
|
|
95
161
|
* The lifecycle stage BEFORE a draft. `propose_blueprint` returns
|
|
@@ -161,7 +227,83 @@ export interface BuilderHandoff {
|
|
|
161
227
|
packageId?: string;
|
|
162
228
|
}
|
|
163
229
|
export declare function detectBuilderHandoff(result: unknown): BuilderHandoff | undefined;
|
|
230
|
+
/**
|
|
231
|
+
* cloud#1658 — the ask agent's `open_record` structured hand-off: the OTHER
|
|
232
|
+
* ending of a write request. Envelope
|
|
233
|
+
* `{ status:'record_handoff', handoff:'record', objectName, recordId, label?, reason? }`.
|
|
234
|
+
* Lifted so the chat renders an explicit "打开这条记录 →" action landing on the
|
|
235
|
+
* record the agent already resolved — the whole point is that the user never
|
|
236
|
+
* re-finds a record the agent has in hand. Both ids are REQUIRED: a hand-off
|
|
237
|
+
* with either missing is dropped here exactly as the server refuses to emit
|
|
238
|
+
* one, because a card pointing nowhere is worse than the prose it replaces.
|
|
239
|
+
*/
|
|
240
|
+
export interface RecordHandoff {
|
|
241
|
+
objectName: string;
|
|
242
|
+
recordId: string;
|
|
243
|
+
label?: string;
|
|
244
|
+
reason?: string;
|
|
245
|
+
}
|
|
246
|
+
export declare function detectRecordHandoff(result: unknown): RecordHandoff | undefined;
|
|
164
247
|
export declare function detectProposedChanges(result: unknown): ProposedChanges | undefined;
|
|
248
|
+
/**
|
|
249
|
+
* objectui#5695 — the terminal verdict of a confirm-replay.
|
|
250
|
+
*
|
|
251
|
+
* When the user approves a 确认修改 card, the runtime re-dispatches the
|
|
252
|
+
* proposal deterministically and appends the result under a synthetic
|
|
253
|
+
* `replay_<turn>_<i>` tool-call id (cloud `runApprovedProposalReplay`). The
|
|
254
|
+
* envelope is the ordinary authoring envelope — `status:'published'`,
|
|
255
|
+
* or `status:'drafted'` optionally stamped `publishFailed:true` +
|
|
256
|
+
* `publishOutcome`/`publishError` when the in-turn publish rolled back
|
|
257
|
+
* (cloud#1467). Lifted into a dedicated shape so the confirm card can render
|
|
258
|
+
* a UI-owned terminal state — the layer a model cannot narrate over.
|
|
259
|
+
*/
|
|
260
|
+
export interface ReplayOutcome {
|
|
261
|
+
kind: 'published' | 'drafted' | 'failed';
|
|
262
|
+
/** Machine verdict of a failed publish (`rejected` / `rolled_back` / `nothing_published`). */
|
|
263
|
+
outcome?: string;
|
|
264
|
+
/** First line of `publishError`, for the 未生效 headline. */
|
|
265
|
+
error?: string;
|
|
266
|
+
/** Owning package of a drafted outcome, for the inline publish affordance. */
|
|
267
|
+
packageId?: string;
|
|
268
|
+
/**
|
|
269
|
+
* The replay DISPATCH itself errored (bare `{error: …}` envelope) rather
|
|
270
|
+
* than the publish being refused — measured live 2026-08-24: an apply_edit
|
|
271
|
+
* replay carrying a blueprint-local object name errored `object "task" not
|
|
272
|
+
* found`, after which the MODEL self-repaired with different tool calls
|
|
273
|
+
* that succeeded. A dispatch error is therefore only provisionally
|
|
274
|
+
* `failed`: the card walk may supersede it with a later successful
|
|
275
|
+
* authoring verdict from the same turn (see `detectAuthoringVerdict`),
|
|
276
|
+
* so the card never says 未生效 over a change that actually landed.
|
|
277
|
+
*/
|
|
278
|
+
dispatchError?: boolean;
|
|
279
|
+
}
|
|
280
|
+
export declare function detectReplayOutcome(toolCallId: string | undefined, result: unknown): ReplayOutcome | undefined;
|
|
281
|
+
/**
|
|
282
|
+
* objectui#5695 — classify ANY tool result as an authoring verdict, for the
|
|
283
|
+
* confirm card's self-repair supersede: after a replay DISPATCH error, the
|
|
284
|
+
* model may land the same change through different tool calls; those results
|
|
285
|
+
* carry the ordinary authoring envelope, and the latest one in the turn is
|
|
286
|
+
* the truthful terminal state for the card.
|
|
287
|
+
*/
|
|
288
|
+
export declare function detectAuthoringVerdict(result: unknown): {
|
|
289
|
+
kind: 'published' | 'drafted' | 'failed';
|
|
290
|
+
packageId?: string;
|
|
291
|
+
} | undefined;
|
|
292
|
+
/**
|
|
293
|
+
* objectui#5799 — did this tool result finish a WHOLE-APP build, and for which
|
|
294
|
+
* package? Posture-independent on purpose: an auto-publish environment
|
|
295
|
+
* rewrites the apply_blueprint envelope to `status:'published'` (keeping
|
|
296
|
+
* `drafted[]` + `packageId`), so keying the built-moment transition on
|
|
297
|
+
* `draftReview` (drafted-only) missed every staging/cloud build — measured
|
|
298
|
+
* live: reopening a built conversation stayed on the full page.
|
|
299
|
+
*
|
|
300
|
+
* objectui#10109 — an envelope that says `kind: 'edit'` is an INCREMENTAL
|
|
301
|
+
* edit (`apply_edit`), never a whole-app build, even when its `drafted[]`
|
|
302
|
+
* honestly lists the `app` artifact it re-staged (an `add_object` op merges
|
|
303
|
+
* the nav). The producer declares the difference on the envelope, so it is
|
|
304
|
+
* read here rather than inferred from which artifact types were staged.
|
|
305
|
+
*/
|
|
306
|
+
export declare function detectBuiltAppPackage(result: unknown): string | undefined;
|
|
165
307
|
export declare function detectDraftResult(result: unknown): DraftReview | undefined;
|
|
166
308
|
/**
|
|
167
309
|
* Synthesize a COMPLETED build-progress summary from a persisted apply_blueprint
|
|
@@ -171,7 +313,9 @@ export declare function detectDraftResult(result: unknown): DraftReview | undefi
|
|
|
171
313
|
* reconstruct the done-state from the draft result, which IS persisted, so the
|
|
172
314
|
* summary + its preview/open affordances survive a refresh. Only whole-app
|
|
173
315
|
* builds (a draft set that includes an `app`) get a panel — incremental edits
|
|
174
|
-
* keep their draft card but no build tree, matching the live behaviour.
|
|
316
|
+
* keep their draft card but no build tree, matching the live behaviour. An
|
|
317
|
+
* edit is known by the producer's `kind: 'edit'`, not by its staged types: it
|
|
318
|
+
* can re-stage the `app` artifact too (objectui#10109).
|
|
175
319
|
*/
|
|
176
320
|
export declare function buildProgressFromDraftReview(draft: DraftReview | undefined): ChatBuildProgress | undefined;
|
|
177
321
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mapMessages.d.ts","sourceRoot":"","sources":["../src/mapMessages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAc,iBAAiB,EAAoC,MAAM,mBAAmB,CAAC;AAE1I,UAAU,OAAO;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"mapMessages.d.ts","sourceRoot":"","sources":["../src/mapMessages.ts"],"names":[],"mappings":"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"}
|
package/dist/tool-display.d.ts
CHANGED
|
@@ -9,15 +9,39 @@
|
|
|
9
9
|
* peel the envelope, parse the inner JSON when possible, and produce a
|
|
10
10
|
* human-friendly title for snake_case tool names.
|
|
11
11
|
*/
|
|
12
|
+
/**
|
|
13
|
+
* A translator for tool titles. Takes the i18n key and the English fallback
|
|
14
|
+
* this module would otherwise have produced, and returns whatever the active
|
|
15
|
+
* locale has — or the fallback when that locale carries no entry.
|
|
16
|
+
*
|
|
17
|
+
* Shaped to accept `useSafeTranslate()` directly, so a caller passes the hook's
|
|
18
|
+
* result and nothing else changes.
|
|
19
|
+
*/
|
|
20
|
+
export type ToolTitleTranslator = (key: string, fallback: string) => string;
|
|
21
|
+
/** The i18n key a tool title is looked up under. */
|
|
22
|
+
export declare function toolTitleKey(name: string): string;
|
|
12
23
|
/**
|
|
13
24
|
* Convert a snake_case / kebab-case tool name into a human-readable title.
|
|
14
25
|
*
|
|
26
|
+
* With no translator this is what it always was: an ENGLISH title-caser. That
|
|
27
|
+
* is why a fully Chinese conversation still read
|
|
28
|
+
* `Describe object 已完成 / Visualize data 已完成` (cloud#1658) — every other
|
|
29
|
+
* string on the card was localized and the tool name could not be, because the
|
|
30
|
+
* name never passed through i18n at all. The step the user most needs to read
|
|
31
|
+
* ("what is it doing right now?") was the one left in a foreign language.
|
|
32
|
+
*
|
|
33
|
+
* Pass `translate` (e.g. `useSafeTranslate()`) to look the title up as
|
|
34
|
+
* `chatbot.tool.<tool_name>`; a locale with no entry for that tool falls back
|
|
35
|
+
* to the same English title as before, so packs can be filled in gradually and
|
|
36
|
+
* an unknown//custom tool is never worse off than today.
|
|
37
|
+
*
|
|
15
38
|
* @example
|
|
16
|
-
* humanizeToolName('list_objects')
|
|
17
|
-
* humanizeToolName('query_records')
|
|
18
|
-
* humanizeToolName('describe-api-tool')
|
|
39
|
+
* humanizeToolName('list_objects') // → 'List objects'
|
|
40
|
+
* humanizeToolName('query_records') // → 'Query records'
|
|
41
|
+
* humanizeToolName('describe-api-tool') // → 'Describe API tool'
|
|
42
|
+
* humanizeToolName('describe_object', tt) // → '查看对象结构' (zh)
|
|
19
43
|
*/
|
|
20
|
-
export declare function humanizeToolName(name: string | undefined | null): string;
|
|
44
|
+
export declare function humanizeToolName(name: string | undefined | null, translate?: ToolTitleTranslator): string;
|
|
21
45
|
/**
|
|
22
46
|
* Detect the MCP-style `{ type: 'text', value: '<json|text>' }` envelope used
|
|
23
47
|
* by `@objectstack/service-ai` tool outputs and peel it. When the inner value
|
|
@@ -38,8 +62,17 @@ export declare function summarizeChatError(err: unknown): {
|
|
|
38
62
|
summary: string;
|
|
39
63
|
details?: string;
|
|
40
64
|
};
|
|
41
|
-
/**
|
|
42
|
-
|
|
65
|
+
/**
|
|
66
|
+
* AI quota refusal codes emitted by the cloud token guardrail (HTTP 429).
|
|
67
|
+
*
|
|
68
|
+
* TWO vocabularies, both live. cloud#1238 (the cloud#1168 convergence) landed
|
|
69
|
+
* the SCREAMING_SNAKE ledger codes — which is what a spec-conformant
|
|
70
|
+
* `error.code` must be, an `ErrorCode` ledger member. The lowercase trio is
|
|
71
|
+
* the legacy vocabulary that transition-period producers still emit, so it is
|
|
72
|
+
* KEPT rather than swapped out: dropping it would silently stop parsing every
|
|
73
|
+
* producer that has not converged yet (objectui#3804).
|
|
74
|
+
*/
|
|
75
|
+
export type AiQuotaCode = 'AI_DESIGN_QUOTA_EXHAUSTED' | 'AI_DATA_CHAT_TRIAL_EXHAUSTED' | 'AI_ALLOWANCE_EXHAUSTED' | 'ai_design_quota_exhausted' | 'ai_data_chat_trial_exhausted' | 'ai_allowance_exhausted';
|
|
43
76
|
export interface AiQuotaError {
|
|
44
77
|
code: AiQuotaCode;
|
|
45
78
|
/** Localized (zh) message from the backend. */
|
|
@@ -50,6 +83,31 @@ export interface AiQuotaError {
|
|
|
50
83
|
upgrade: boolean;
|
|
51
84
|
/** Paid tier -> buy a credit top-up pack. */
|
|
52
85
|
topUp: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The allowance replenishes at the next daily reset, so "wait" is a real
|
|
88
|
+
* option alongside the CTA. Only set when the producer sends an actual
|
|
89
|
+
* boolean: the landed envelope carries this inside `error.details`
|
|
90
|
+
* (cloud#1238) and that POSITION is measured, but an absent or
|
|
91
|
+
* otherwise-typed value stays `undefined` rather than being coerced to a
|
|
92
|
+
* `false` no producer declared.
|
|
93
|
+
*
|
|
94
|
+
* ⚠️ objectui#7587 — measured on this tree: NOTHING reads this field once the
|
|
95
|
+
* parse fills it in. `useAiQuotaCopy` (ChatbotEnhanced), the only consumer of
|
|
96
|
+
* the parsed shape's fields, builds the banner from `message` / `messageEn` /
|
|
97
|
+
* `topUp`; the other two `parseAiQuotaError` call sites use the parse as a
|
|
98
|
+
* yes/no predicate. So cloud PR #1852's free-plan inversion (`true` ->
|
|
99
|
+
* `false`, the rolling 7-day window) changes nothing on screen, and the ISO
|
|
100
|
+
* `resetsAt` that producer now sends beside this flag is deliberately NOT
|
|
101
|
+
* read here: with no renderer for it, a read would pin a wire position this
|
|
102
|
+
* repo cannot measure (`objectstack-ai/cloud` is out of scope) and would add
|
|
103
|
+
* a second unread field rather than answer anyone's question. Both halves are
|
|
104
|
+
* pinned — the flag's inertness by
|
|
105
|
+
* `__tests__/ChatbotEnhanced.quotaResetPromise-7587.test.tsx`, the parse's
|
|
106
|
+
* silence about the instant by `tool-display.test.ts`. Wiring reset copy to
|
|
107
|
+
* this BOOLEAN is the one move to avoid: it is `false` for exactly the plan
|
|
108
|
+
* that needs the answer.
|
|
109
|
+
*/
|
|
110
|
+
resetsTonight?: boolean;
|
|
53
111
|
}
|
|
54
112
|
/**
|
|
55
113
|
* Recognize the cloud AI token guardrail's 429 quota refusals so the chat UI can
|
|
@@ -60,26 +118,39 @@ export interface AiQuotaError {
|
|
|
60
118
|
* strip the same retry/format prefixes summarizeChatError handles, locate the
|
|
61
119
|
* JSON object, and find the code in it. Returns null for anything else.
|
|
62
120
|
*
|
|
63
|
-
* ##
|
|
64
|
-
*
|
|
65
|
-
* The two cloud 429 producers fill the same `error` key in OPPOSITE ways
|
|
66
|
-
* ADR-0112
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* |
|
|
74
|
-
*
|
|
75
|
-
* |
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
121
|
+
* ## Four dialects, two vocabularies
|
|
122
|
+
*
|
|
123
|
+
* The two cloud 429 producers fill the same `error` key in OPPOSITE ways
|
|
124
|
+
* (objectui#3491, cloud#944), and ADR-0112's declared envelope has now LANDED
|
|
125
|
+
* on the producer side (cloud#1168 -> cloud PR #1238), adding a fourth
|
|
126
|
+
* dialect: the declared envelope carrying the SCREAMING_SNAKE ledger
|
|
127
|
+
* vocabulary with its companion fields inside `error.details`. All four are
|
|
128
|
+
* read here, because the producers converge asymmetrically and the legacy
|
|
129
|
+
* dialects are still live (objectui#3804):
|
|
130
|
+
*
|
|
131
|
+
* | dialect | shape |
|
|
132
|
+
* |-------------------------------|-------------------------------------------------|
|
|
133
|
+
* | declared envelope + ledger | `{ error: { code: AI_*, message, details } }` |
|
|
134
|
+
* | declared envelope + legacy | `{ success: false, error: { code, message } }` |
|
|
135
|
+
* | flat guardrail | `{ error: CODE, message, upgrade, topUp }` |
|
|
136
|
+
* | service-ai sibling key | `{ error: PROSE, code: CODE }` |
|
|
137
|
+
*
|
|
138
|
+
* Both the code's LOCATION and the recognized code SET widen; an unknown shape
|
|
139
|
+
* still degrades to today's behavior (null).
|
|
140
|
+
*
|
|
141
|
+
* ## What this deliberately does NOT recognize: generic `QUOTA_EXCEEDED`
|
|
142
|
+
*
|
|
143
|
+
* `POST /api/v1/ai/agents/:name/chat`'s per-turn message cap keeps emitting the
|
|
144
|
+
* standard `QUOTA_EXCEEDED` (`error.details.resetAt`, `category: 'rate_limit'`)
|
|
145
|
+
* and did NOT move to the three `AI_*` codes — it has no upgrade / top-up /
|
|
146
|
+
* trial next step, which is exactly the distinction the 2026-08-11 Option A
|
|
147
|
+
* ruling drew when it admitted the three codes to the closed ledger.
|
|
148
|
+
*
|
|
149
|
+
* It is NOT dropped, it is handled one branch along: `isUnsentSendError` +
|
|
150
|
+
* `isRateLimitError` route it to the "you're sending too quickly" notice, with
|
|
151
|
+
* the user's text restored. Returning an `AiQuotaError` for it here would put
|
|
152
|
+
* an "Upgrade plan" CTA in front of a user whose cap resets in a minute.
|
|
153
|
+
* `tool-display.test.ts` pins that routing so the split cannot close silently.
|
|
83
154
|
*
|
|
84
155
|
* ## Parse priority (a total order, deliberately)
|
|
85
156
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-display.d.ts","sourceRoot":"","sources":["../src/tool-display.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAeH;;;;;;;GAOG;AACH,wBAAgB,
|
|
1
|
+
{"version":3,"file":"tool-display.d.ts","sourceRoot":"","sources":["../src/tool-display.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAeH;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;AAE5E,oDAAoD;AACpD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAC/B,SAAS,CAAC,EAAE,mBAAmB,GAC9B,MAAM,CAwBR;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAqCxD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAiCA;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GAEnB,2BAA2B,GAC3B,8BAA8B,GAC9B,wBAAwB,GAExB,2BAA2B,GAC3B,8BAA8B,GAC9B,wBAAwB,CAAC;AAE7B,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,KAAK,EAAE,OAAO,CAAC;IACf;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AA+CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAuDnE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAIvD;AAED,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAIhE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAItD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Locale wiring for `AiPendingActionsInbox` — objectui#7173.
|
|
10
|
+
*
|
|
11
|
+
* A module of its own, the shape `plugin-detail`'s `useDetailTranslation.ts`
|
|
12
|
+
* already uses: the defaults map has to be importable by the test that compares
|
|
13
|
+
* it against the `en` pack, and exporting a non-component from the component
|
|
14
|
+
* file trips `react-refresh/only-export-components`.
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* English fallbacks for every key the inbox reads.
|
|
20
|
+
*
|
|
21
|
+
* `createSafeTranslation` serves these when no `I18nProvider` is mounted — a
|
|
22
|
+
* standalone Studio panel, a host that embeds the inbox without the provider,
|
|
23
|
+
* this package's own tests — so a provider-less render shows English rather
|
|
24
|
+
* than raw keys. Every row here is byte-identical to its `en` pack value: the
|
|
25
|
+
* pack is what the console renders and this map is its stand-in, so the two
|
|
26
|
+
* must not disagree.
|
|
27
|
+
*
|
|
28
|
+
* The four relative-time rows are BORROWED from `detail.*` rather than minted
|
|
29
|
+
* under this namespace. They already existed, translated, in all ten packs, and
|
|
30
|
+
* cross-package borrowing is this repo's settled convention — `ObjectGrid`,
|
|
31
|
+
* `ObjectKanban`, `ObjectTree`, `ListView`, `ObjectView`, `NavigationOverlay`
|
|
32
|
+
* and `RecordAttachmentsPanel` all resolve `detail.*` from outside
|
|
33
|
+
* `plugin-detail`. One phrase on one kind of control should not get a second
|
|
34
|
+
* translation that can drift from the first.
|
|
35
|
+
*
|
|
36
|
+
* ⛔ The five relative-time helpers in this repo are NOT unified (objectui#7173's
|
|
37
|
+
* triage ruling): they differ in real behaviour — `Math.round` in this inbox vs
|
|
38
|
+
* `Math.floor` in `plugin-detail`, 45s/30d vs 60s/7d, different tails — and
|
|
39
|
+
* normalising them is a behaviour change that needs its own card. Only the
|
|
40
|
+
* OUTPUT is translated; `AiPendingActionsInbox.formatRelative` keeps its own
|
|
41
|
+
* arithmetic, pinned by `__tests__/AiPendingActionsInbox.i18n.test.tsx`.
|
|
42
|
+
*
|
|
43
|
+
* Exported from this MODULE, not from the package barrel (`src/index.tsx`
|
|
44
|
+
* names its exports one by one), so it stays off the published API surface
|
|
45
|
+
* while `__tests__/AiPendingActionsInbox.i18n.test.tsx` can compare it row by
|
|
46
|
+
* row against the `en` pack — the invariant
|
|
47
|
+
* `app-shell/src/__tests__/defaults-maps-mirror-en-pack.test.tsx` holds the
|
|
48
|
+
* detail / list / designer maps to. A row that disagrees with the pack renders
|
|
49
|
+
* two different labels for one control and nothing else would see it.
|
|
50
|
+
*/
|
|
51
|
+
export declare const AI_APPROVALS_DEFAULT_TRANSLATIONS: Record<string, string>;
|
|
52
|
+
/**
|
|
53
|
+
* Safe wrapper for `useObjectTranslation` that falls back to the map above when
|
|
54
|
+
* no `I18nProvider` is mounted. Delegates to `@object-ui/i18n`'s
|
|
55
|
+
* `createSafeTranslation` — the factory form, not the per-call
|
|
56
|
+
* `useSafeTranslate(key, fallback)`: the inbox interpolates `{{count}}`,
|
|
57
|
+
* `{{id}}`, `{{message}}`, `{{tool}}` and `{{object}}`, and `useSafeTranslate`
|
|
58
|
+
* has no options argument, so those holes would reach the DOM raw. No inline
|
|
59
|
+
* `defaultValue` anywhere either (objectui#3517).
|
|
60
|
+
*/
|
|
61
|
+
export declare const useAiApprovalsTranslation: () => {
|
|
62
|
+
t: (key: string, options?: Record<string, unknown>) => string;
|
|
63
|
+
language: string;
|
|
64
|
+
} | {
|
|
65
|
+
t: import('i18next').TFunction<string, undefined>;
|
|
66
|
+
language: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* The `t` the inbox's module-level helpers take.
|
|
70
|
+
*
|
|
71
|
+
* `formatRelative` and `statusLabel` are plain functions, not hooks, so the
|
|
72
|
+
* component reads the hook once and passes `t` down — the same shape
|
|
73
|
+
* `ActivityTimeline` uses for its own formatter.
|
|
74
|
+
*/
|
|
75
|
+
export type InboxTranslate = (key: string, options?: Record<string, unknown>) => string;
|
|
76
|
+
//# sourceMappingURL=useAiApprovalsTranslation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAiApprovalsTranslation.d.ts","sourceRoot":"","sources":["../src/useAiApprovalsTranslation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,iCAAiC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqDpE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB;4BAjHrC,CAAC;;;;;CAoHD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC"}
|
package/dist/useAiModels.d.ts
CHANGED
package/dist/useHitlInChat.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ChatMessage, ToolDecisionState } from './ChatbotEnhanced';
|
|
2
|
-
import { ApproveOutcome, RejectOutcome } from './usePendingActions';
|
|
1
|
+
import { ChatMessage, ToolDecisionState } from './ChatbotEnhanced.js';
|
|
2
|
+
import { ApproveOutcome, RejectOutcome } from './usePendingActions.js';
|
|
3
3
|
export type { ToolDecisionState };
|
|
4
4
|
export interface UseHitlInChatOptions {
|
|
5
5
|
/**
|