@tangle-network/agent-app 0.7.2 → 0.8.1

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.
@@ -0,0 +1,236 @@
1
+ // src/assets/schema.ts
2
+ import { z } from "zod";
3
+ var BrandTokensSchema = z.object({
4
+ primaryColor: z.string(),
5
+ accentColor: z.string(),
6
+ textColor: z.string(),
7
+ fontFamily: z.string(),
8
+ logoUrl: z.string().optional(),
9
+ businessName: z.string(),
10
+ voice: z.string()
11
+ });
12
+ var EmailHeroSectionSchema = z.object({
13
+ type: z.literal("hero"),
14
+ headline: z.string(),
15
+ subheadline: z.string().optional(),
16
+ imageUrl: z.string().optional(),
17
+ ctaLabel: z.string().optional(),
18
+ ctaUrl: z.string().optional()
19
+ });
20
+ var EmailBodySectionSchema = z.object({
21
+ type: z.literal("body"),
22
+ text: z.string()
23
+ });
24
+ var EmailFeatureSectionSchema = z.object({
25
+ type: z.literal("feature"),
26
+ headline: z.string(),
27
+ description: z.string(),
28
+ imageUrl: z.string().optional()
29
+ });
30
+ var EmailTestimonialSectionSchema = z.object({
31
+ type: z.literal("testimonial"),
32
+ quote: z.string(),
33
+ author: z.string(),
34
+ role: z.string().optional(),
35
+ avatarUrl: z.string().optional()
36
+ });
37
+ var EmailCtaSectionSchema = z.object({
38
+ type: z.literal("cta"),
39
+ label: z.string(),
40
+ url: z.string(),
41
+ subtext: z.string().optional()
42
+ });
43
+ var EmailDividerSectionSchema = z.object({
44
+ type: z.literal("divider")
45
+ });
46
+ var EmailSectionSchema = z.discriminatedUnion("type", [
47
+ EmailHeroSectionSchema,
48
+ EmailBodySectionSchema,
49
+ EmailFeatureSectionSchema,
50
+ EmailTestimonialSectionSchema,
51
+ EmailCtaSectionSchema,
52
+ EmailDividerSectionSchema
53
+ ]);
54
+ var EmailContentSchema = z.object({
55
+ subject: z.string(),
56
+ preheader: z.string().optional(),
57
+ sections: z.array(EmailSectionSchema)
58
+ });
59
+ var ImageBackgroundSchema = z.discriminatedUnion("type", [
60
+ z.object({ type: z.literal("color"), value: z.string() }),
61
+ z.object({ type: z.literal("gradient"), from: z.string(), to: z.string(), direction: z.string().optional() }),
62
+ z.object({ type: z.literal("image"), url: z.string(), overlay: z.string().optional(), overlayOpacity: z.number().optional() })
63
+ ]);
64
+ var ImageTextLayerSchema = z.object({
65
+ type: z.literal("text"),
66
+ text: z.string(),
67
+ fontSize: z.number().optional(),
68
+ fontWeight: z.enum(["normal", "bold"]).optional(),
69
+ color: z.string().optional(),
70
+ x: z.number(),
71
+ y: z.number(),
72
+ width: z.number().optional(),
73
+ align: z.enum(["left", "center", "right"]).optional()
74
+ });
75
+ var ImageImageLayerSchema = z.object({
76
+ type: z.literal("image"),
77
+ url: z.string(),
78
+ x: z.number(),
79
+ y: z.number(),
80
+ width: z.number(),
81
+ height: z.number(),
82
+ opacity: z.number().optional()
83
+ });
84
+ var ImageShapeLayerSchema = z.object({
85
+ type: z.literal("shape"),
86
+ shape: z.enum(["rect", "circle", "rounded-rect"]),
87
+ x: z.number(),
88
+ y: z.number(),
89
+ width: z.number(),
90
+ height: z.number(),
91
+ fill: z.string().optional(),
92
+ opacity: z.number().optional()
93
+ });
94
+ var ImageLogoLayerSchema = z.object({
95
+ type: z.literal("logo"),
96
+ x: z.number(),
97
+ y: z.number(),
98
+ width: z.number().optional()
99
+ });
100
+ var ImageLayerSchema = z.discriminatedUnion("type", [
101
+ ImageTextLayerSchema,
102
+ ImageImageLayerSchema,
103
+ ImageShapeLayerSchema,
104
+ ImageLogoLayerSchema
105
+ ]);
106
+ var ImageSlideSchema = z.object({
107
+ background: ImageBackgroundSchema,
108
+ layers: z.array(ImageLayerSchema)
109
+ });
110
+ var ImageContentSchema = z.object({
111
+ slides: z.array(ImageSlideSchema).min(1)
112
+ });
113
+ var VideoTextAnimationSceneSchema = z.object({
114
+ type: z.literal("text-animation"),
115
+ durationSeconds: z.number().positive(),
116
+ headline: z.string(),
117
+ subtext: z.string().optional(),
118
+ animation: z.enum(["fade", "slide-up", "typewriter"]).optional(),
119
+ background: ImageBackgroundSchema.optional()
120
+ });
121
+ var VideoImageRevealSceneSchema = z.object({
122
+ type: z.literal("image-reveal"),
123
+ durationSeconds: z.number().positive(),
124
+ imageUrl: z.string(),
125
+ caption: z.string().optional()
126
+ });
127
+ var VideoSlideSceneSchema = z.object({
128
+ type: z.literal("slide"),
129
+ durationSeconds: z.number().positive(),
130
+ slide: ImageSlideSchema
131
+ });
132
+ var VideoCountdownSceneSchema = z.object({
133
+ type: z.literal("countdown"),
134
+ durationSeconds: z.number().positive(),
135
+ from: z.number().int().positive(),
136
+ label: z.string().optional()
137
+ });
138
+ var VideoSceneSchema = z.discriminatedUnion("type", [
139
+ VideoTextAnimationSceneSchema,
140
+ VideoImageRevealSceneSchema,
141
+ VideoSlideSceneSchema,
142
+ VideoCountdownSceneSchema
143
+ ]);
144
+ var VideoCaptionSchema = z.object({
145
+ startSeconds: z.number().nonnegative(),
146
+ endSeconds: z.number().positive(),
147
+ text: z.string()
148
+ });
149
+ var VideoContentSchema = z.object({
150
+ durationSeconds: z.number().positive(),
151
+ scenes: z.array(VideoSceneSchema).min(1),
152
+ audioUrl: z.string().optional(),
153
+ captions: z.array(VideoCaptionSchema).optional(),
154
+ renderedUrl: z.string().optional()
155
+ });
156
+ var CopyContentSchema = z.object({
157
+ headline: z.string(),
158
+ body: z.string(),
159
+ hashtags: z.array(z.string()).optional(),
160
+ platform: z.enum(["instagram", "tiktok", "x", "linkedin", "sms", "email-subject"]),
161
+ characterCount: z.number().optional()
162
+ });
163
+ var ApprovalEventSchema = z.object({
164
+ assetId: z.string(),
165
+ variantId: z.string().optional(),
166
+ action: z.enum(["approved", "rejected", "edited", "scheduled"]),
167
+ editedFields: z.array(z.string()).optional(),
168
+ userId: z.string(),
169
+ timestamp: z.string()
170
+ });
171
+ var ConversionMetricsSchema = z.object({
172
+ impressions: z.number().nonnegative(),
173
+ clicks: z.number().nonnegative(),
174
+ conversions: z.number().nonnegative(),
175
+ ctr: z.number().nonnegative(),
176
+ cvr: z.number().nonnegative()
177
+ });
178
+ var AssetFormatValues = [
179
+ "email",
180
+ "image:feed",
181
+ "image:story",
182
+ "image:carousel",
183
+ "video:reel",
184
+ "video:feed",
185
+ "copy:caption",
186
+ "copy:headline",
187
+ "copy:sms"
188
+ ];
189
+ var ContentSchemaByFormat = {
190
+ email: EmailContentSchema,
191
+ "image:feed": ImageContentSchema,
192
+ "image:story": ImageContentSchema,
193
+ "image:carousel": ImageContentSchema,
194
+ "video:reel": VideoContentSchema,
195
+ "video:feed": VideoContentSchema,
196
+ "copy:caption": CopyContentSchema,
197
+ "copy:headline": CopyContentSchema,
198
+ "copy:sms": CopyContentSchema
199
+ };
200
+ var AssetSpecBaseSchema = z.object({
201
+ id: z.string(),
202
+ workspaceId: z.string(),
203
+ campaignId: z.string().optional(),
204
+ format: z.enum(AssetFormatValues),
205
+ brand: BrandTokensSchema,
206
+ status: z.enum(["draft", "pending_review", "approved", "rejected", "scheduled", "published"]),
207
+ scheduledAt: z.string().optional(),
208
+ createdAt: z.string(),
209
+ updatedAt: z.string()
210
+ });
211
+ function parseAssetSpec(raw) {
212
+ const base = AssetSpecBaseSchema.parse(raw);
213
+ const contentSchema = ContentSchemaByFormat[base.format];
214
+ const content = contentSchema.parse(raw.content);
215
+ return { ...base, content };
216
+ }
217
+ function safeParseAssetSpec(raw) {
218
+ try {
219
+ return parseAssetSpec(raw);
220
+ } catch {
221
+ return null;
222
+ }
223
+ }
224
+
225
+ export {
226
+ BrandTokensSchema,
227
+ EmailContentSchema,
228
+ ImageContentSchema,
229
+ VideoContentSchema,
230
+ CopyContentSchema,
231
+ ApprovalEventSchema,
232
+ ConversionMetricsSchema,
233
+ parseAssetSpec,
234
+ safeParseAssetSpec
235
+ };
236
+ //# sourceMappingURL=chunk-5PTGEJZL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/assets/schema.ts"],"sourcesContent":["import { z } from 'zod'\nimport type { AssetSpec, AssetFormat } from './types'\n\n// --- Brand ---\n\nexport const BrandTokensSchema = z.object({\n primaryColor: z.string(),\n accentColor: z.string(),\n textColor: z.string(),\n fontFamily: z.string(),\n logoUrl: z.string().optional(),\n businessName: z.string(),\n voice: z.string(),\n})\n\n// --- Email ---\n\nconst EmailHeroSectionSchema = z.object({\n type: z.literal('hero'),\n headline: z.string(),\n subheadline: z.string().optional(),\n imageUrl: z.string().optional(),\n ctaLabel: z.string().optional(),\n ctaUrl: z.string().optional(),\n})\n\nconst EmailBodySectionSchema = z.object({\n type: z.literal('body'),\n text: z.string(),\n})\n\nconst EmailFeatureSectionSchema = z.object({\n type: z.literal('feature'),\n headline: z.string(),\n description: z.string(),\n imageUrl: z.string().optional(),\n})\n\nconst EmailTestimonialSectionSchema = z.object({\n type: z.literal('testimonial'),\n quote: z.string(),\n author: z.string(),\n role: z.string().optional(),\n avatarUrl: z.string().optional(),\n})\n\nconst EmailCtaSectionSchema = z.object({\n type: z.literal('cta'),\n label: z.string(),\n url: z.string(),\n subtext: z.string().optional(),\n})\n\nconst EmailDividerSectionSchema = z.object({\n type: z.literal('divider'),\n})\n\nconst EmailSectionSchema = z.discriminatedUnion('type', [\n EmailHeroSectionSchema,\n EmailBodySectionSchema,\n EmailFeatureSectionSchema,\n EmailTestimonialSectionSchema,\n EmailCtaSectionSchema,\n EmailDividerSectionSchema,\n])\n\nexport const EmailContentSchema = z.object({\n subject: z.string(),\n preheader: z.string().optional(),\n sections: z.array(EmailSectionSchema),\n})\n\n// --- Image ---\n\nconst ImageBackgroundSchema = z.discriminatedUnion('type', [\n z.object({ type: z.literal('color'), value: z.string() }),\n z.object({ type: z.literal('gradient'), from: z.string(), to: z.string(), direction: z.string().optional() }),\n z.object({ type: z.literal('image'), url: z.string(), overlay: z.string().optional(), overlayOpacity: z.number().optional() }),\n])\n\nconst ImageTextLayerSchema = z.object({\n type: z.literal('text'),\n text: z.string(),\n fontSize: z.number().optional(),\n fontWeight: z.enum(['normal', 'bold']).optional(),\n color: z.string().optional(),\n x: z.number(),\n y: z.number(),\n width: z.number().optional(),\n align: z.enum(['left', 'center', 'right']).optional(),\n})\n\nconst ImageImageLayerSchema = z.object({\n type: z.literal('image'),\n url: z.string(),\n x: z.number(),\n y: z.number(),\n width: z.number(),\n height: z.number(),\n opacity: z.number().optional(),\n})\n\nconst ImageShapeLayerSchema = z.object({\n type: z.literal('shape'),\n shape: z.enum(['rect', 'circle', 'rounded-rect']),\n x: z.number(),\n y: z.number(),\n width: z.number(),\n height: z.number(),\n fill: z.string().optional(),\n opacity: z.number().optional(),\n})\n\nconst ImageLogoLayerSchema = z.object({\n type: z.literal('logo'),\n x: z.number(),\n y: z.number(),\n width: z.number().optional(),\n})\n\nconst ImageLayerSchema = z.discriminatedUnion('type', [\n ImageTextLayerSchema,\n ImageImageLayerSchema,\n ImageShapeLayerSchema,\n ImageLogoLayerSchema,\n])\n\nconst ImageSlideSchema = z.object({\n background: ImageBackgroundSchema,\n layers: z.array(ImageLayerSchema),\n})\n\nexport const ImageContentSchema = z.object({\n slides: z.array(ImageSlideSchema).min(1),\n})\n\n// --- Video ---\n\nconst VideoTextAnimationSceneSchema = z.object({\n type: z.literal('text-animation'),\n durationSeconds: z.number().positive(),\n headline: z.string(),\n subtext: z.string().optional(),\n animation: z.enum(['fade', 'slide-up', 'typewriter']).optional(),\n background: ImageBackgroundSchema.optional(),\n})\n\nconst VideoImageRevealSceneSchema = z.object({\n type: z.literal('image-reveal'),\n durationSeconds: z.number().positive(),\n imageUrl: z.string(),\n caption: z.string().optional(),\n})\n\nconst VideoSlideSceneSchema = z.object({\n type: z.literal('slide'),\n durationSeconds: z.number().positive(),\n slide: ImageSlideSchema,\n})\n\nconst VideoCountdownSceneSchema = z.object({\n type: z.literal('countdown'),\n durationSeconds: z.number().positive(),\n from: z.number().int().positive(),\n label: z.string().optional(),\n})\n\nconst VideoSceneSchema = z.discriminatedUnion('type', [\n VideoTextAnimationSceneSchema,\n VideoImageRevealSceneSchema,\n VideoSlideSceneSchema,\n VideoCountdownSceneSchema,\n])\n\nconst VideoCaptionSchema = z.object({\n startSeconds: z.number().nonnegative(),\n endSeconds: z.number().positive(),\n text: z.string(),\n})\n\nexport const VideoContentSchema = z.object({\n durationSeconds: z.number().positive(),\n scenes: z.array(VideoSceneSchema).min(1),\n audioUrl: z.string().optional(),\n captions: z.array(VideoCaptionSchema).optional(),\n renderedUrl: z.string().optional(),\n})\n\n// --- Copy ---\n\nexport const CopyContentSchema = z.object({\n headline: z.string(),\n body: z.string(),\n hashtags: z.array(z.string()).optional(),\n platform: z.enum(['instagram', 'tiktok', 'x', 'linkedin', 'sms', 'email-subject']),\n characterCount: z.number().optional(),\n})\n\n// --- Approval ---\n\nexport const ApprovalEventSchema = z.object({\n assetId: z.string(),\n variantId: z.string().optional(),\n action: z.enum(['approved', 'rejected', 'edited', 'scheduled']),\n editedFields: z.array(z.string()).optional(),\n userId: z.string(),\n timestamp: z.string(),\n})\n\nexport const ConversionMetricsSchema = z.object({\n impressions: z.number().nonnegative(),\n clicks: z.number().nonnegative(),\n conversions: z.number().nonnegative(),\n ctr: z.number().nonnegative(),\n cvr: z.number().nonnegative(),\n})\n\n// --- Content map for discriminated parse ---\n\nconst AssetFormatValues = [\n 'email',\n 'image:feed',\n 'image:story',\n 'image:carousel',\n 'video:reel',\n 'video:feed',\n 'copy:caption',\n 'copy:headline',\n 'copy:sms',\n] as const\n\nconst ContentSchemaByFormat = {\n email: EmailContentSchema,\n 'image:feed': ImageContentSchema,\n 'image:story': ImageContentSchema,\n 'image:carousel': ImageContentSchema,\n 'video:reel': VideoContentSchema,\n 'video:feed': VideoContentSchema,\n 'copy:caption': CopyContentSchema,\n 'copy:headline': CopyContentSchema,\n 'copy:sms': CopyContentSchema,\n} as const\n\nconst AssetSpecBaseSchema = z.object({\n id: z.string(),\n workspaceId: z.string(),\n campaignId: z.string().optional(),\n format: z.enum(AssetFormatValues),\n brand: BrandTokensSchema,\n status: z.enum(['draft', 'pending_review', 'approved', 'rejected', 'scheduled', 'published']),\n scheduledAt: z.string().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n})\n\n/**\n * Validates an unknown value as an AssetSpec, including format-specific\n * content validation. Throws ZodError on invalid input.\n */\nexport function parseAssetSpec(raw: unknown): AssetSpec {\n const base = AssetSpecBaseSchema.parse(raw)\n const contentSchema = ContentSchemaByFormat[base.format]\n const content = contentSchema.parse((raw as Record<string, unknown>).content)\n return { ...base, content } as AssetSpec\n}\n\n/**\n * Safe parse — returns null instead of throwing.\n */\nexport function safeParseAssetSpec(raw: unknown): AssetSpec | null {\n try {\n return parseAssetSpec(raw)\n } catch {\n return null\n }\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -16,7 +16,9 @@ export { HubExecClient, HubExecClientOptions, HubExecErrorCode, HubExecResult, H
16
16
  export { CompleteMissionInput, CreateMissionInput, DEFAULT_MISSION_STEP_KINDS, InMemoryMissionStore, MISSION_CONTROL_CHANNEL_ID, MissionApprovalsPort, MissionAuditEvent, MissionConcurrencyError, MissionCostLedger, MissionEngine, MissionEngineOptions, MissionEventSink, MissionGateKind, MissionGateOptions, MissionGateProposal, MissionOutcome, MissionPlanRunOptions, MissionProposalResolution, MissionRecord, MissionService, MissionServiceOptions, MissionState, MissionStatus, MissionStep, MissionStepState, MissionStepStatus, MissionStorePort, MissionStreamEvent, MissionStreamStatus, MissionStreamStep, MissionStreamStepStatus, MissionUpdateGuard, MissionUpdatePatch, ParseMissionBlocksOptions, ParsedMission, ParsedMissionStep, PlanOutcome, RetryableStepError, SandboxDispatch, SandboxDispatchDoneResult, SandboxDispatchInProgressResult, SandboxDispatchInput, SandboxDispatchResult, SetStepStatusPatch, StepGateClassification, StepOutcome, applyMissionEvent, asMissionStreamEvent, budgetGateProposalId, buildAgentMissionPlan, createInMemoryMissionStore, createMissionEngine, createMissionService, isMissionStopRequested, isMissionTerminal, mergeMissionState, noopEventSink, parseMissionBlocks, parseSessionStreamEnvelope, reduceMissionEvents, stepGateProposalId, volumeGateProposalId } from './missions/index.js';
17
17
  export { CookieOptions, JsonObject, KvLike, RateLimitResult, RequestContext, SecurityHeaderOptions, addSecurityHeaders, checkRateLimit, clearCookieHeader, extractRequestContext, parseJsonObjectBody, readCookieValue, requireString, serializeCookie } from './web/index.js';
18
18
  export { BuildRedactedDocumentOptions, DEFAULT_REDACTION_PATTERNS, RedactForIngestionOptions, RedactedDocSegment, RedactedDocument, RedactionPattern, RedactionSpan, RevealResult, RevealSpanOptions, buildRedactedDocument, detectSpans, maskSpans, redactForIngestion, revealSpan } from './redact/index.js';
19
+ export { ApprovalEvent, ApprovalEventSchema, AssetContentMap, AssetFormat, AssetSpec, AssetStatus, AssetVariant, BrandTokens, BrandTokensSchema, ConversionMetrics, ConversionMetricsSchema, CopyContent, CopyContentSchema, CopyPlatform, EmailBodySection, EmailContent, EmailContentSchema, EmailCtaSection, EmailDividerSection, EmailFeatureSection, EmailHeroSection, EmailSection, EmailTestimonialSection, ImageBackground, ImageContent, ImageContentSchema, ImageImageLayer, ImageLayer, ImageLayerType, ImageLogoLayer, ImageShapeLayer, ImageSlide, ImageTextLayer, VideoCaption, VideoContent, VideoContentSchema, VideoCountdownScene, VideoImageRevealScene, VideoScene, VideoSlideScene, VideoTextAnimationScene, parseAssetSpec, safeParseAssetSpec } from './assets/index.js';
19
20
  export { C as CatalogModel, M as ModelCatalog, R as RouterModel, _ as __resetCatalogCache, b as buildCatalog, f as fetchModelCatalog, n as normalizeModelId } from './model-catalog-BEAEVDaa.js';
20
21
  export { CompletionRequirement, CompletionVerdict, CorrectnessChecker, ProducedState, RuntimeEventLike, SatisfiedBy, TaskGold, createLlmCorrectnessChecker, extractProducedState, verifyCompletion, weightedComposite } from '@tangle-network/agent-eval';
21
22
  export { C as CreateTangleRouterModelConfigOptions, D as DEFAULT_TANGLE_BILLING_ENFORCEMENT_ENV_VAR, a as DEFAULT_TANGLE_ROUTER_BASE_URL, R as ResolveModelOptions, b as ResolveUserTangleExecutionKeyForUserOptions, c as ResolveUserTangleExecutionKeyOptions, d as ResolvedTangleExecutionKey, T as TangleBillingEnforcementOptions, e as TangleExecutionEnvironment, f as TangleExecutionKeyError, g as TangleExecutionKeyErrorCode, h as TangleExecutionKeyHttpError, i as TangleExecutionKeySource, j as TangleModelConfig, k as createTangleRouterModelConfig, l as isTangleBillingEnforcementDisabled, m as isTangleExecutionKeyError, r as resolveTangleExecutionEnvironment, n as resolveTangleModelConfig, o as resolveUserTangleExecutionKey, p as resolveUserTangleExecutionKeyForUser, t as tangleExecutionKeyHttpError } from './model-CKzniMMr.js';
22
23
  import '@tangle-network/agent-knowledge';
24
+ import 'zod';
package/dist/index.js CHANGED
@@ -38,6 +38,17 @@ import {
38
38
  redactForIngestion,
39
39
  revealSpan
40
40
  } from "./chunk-5RMIUJDI.js";
41
+ import {
42
+ ApprovalEventSchema,
43
+ BrandTokensSchema,
44
+ ConversionMetricsSchema,
45
+ CopyContentSchema,
46
+ EmailContentSchema,
47
+ ImageContentSchema,
48
+ VideoContentSchema,
49
+ parseAssetSpec,
50
+ safeParseAssetSpec
51
+ } from "./chunk-5PTGEJZL.js";
41
52
  import {
42
53
  createKnowledgeLoop,
43
54
  createReviewerDecider,
@@ -176,6 +187,10 @@ import {
176
187
  } from "./chunk-ZXNXAQAH.js";
177
188
  export {
178
189
  APP_TOOL_NAMES,
190
+ ApprovalEventSchema,
191
+ BrandTokensSchema,
192
+ ConversionMetricsSchema,
193
+ CopyContentSchema,
179
194
  DEFAULT_APP_TOOL_PATHS,
180
195
  DEFAULT_HARNESS,
181
196
  DEFAULT_HEADER_NAMES,
@@ -185,7 +200,9 @@ export {
185
200
  DEFAULT_TANGLE_ROUTER_BASE_URL,
186
201
  DELEGATION_MCP_SERVER_KEY,
187
202
  DELEGATION_TOOLS,
203
+ EmailContentSchema,
188
204
  HubExecClient,
205
+ ImageContentSchema,
189
206
  KNOWN_HARNESSES,
190
207
  MISSION_CONTROL_CHANNEL_ID,
191
208
  MissionConcurrencyError,
@@ -195,6 +212,7 @@ export {
195
212
  TURN_EVENTS_MIGRATION_SQL,
196
213
  TangleExecutionKeyError,
197
214
  ToolInputError,
215
+ VideoContentSchema,
198
216
  __resetCatalogCache,
199
217
  addSecurityHeaders,
200
218
  agentAppConfigJsonSchema,
@@ -281,6 +299,7 @@ export {
281
299
  normalizeTime,
282
300
  normalizeToolEvent,
283
301
  outcomeStatus,
302
+ parseAssetSpec,
284
303
  parseJsonObjectBody,
285
304
  parseMissionBlocks,
286
305
  parseSessionStreamEnvelope,
@@ -304,6 +323,7 @@ export {
304
323
  revealSpan,
305
324
  reviewCandidate,
306
325
  runAppToolLoop,
326
+ safeParseAssetSpec,
307
327
  serializeCookie,
308
328
  stepGateProposalId,
309
329
  streamAppToolLoop,
@@ -90,6 +90,35 @@ interface ProviderLogoProps {
90
90
  /** Real brand mark when we have one; tinted monogram otherwise. */
91
91
  declare function ProviderLogo({ provider, size }: ProviderLogoProps): ReactNode;
92
92
 
93
+ /**
94
+ * Smooth text reveal — turns chunky network deltas into a continuous
95
+ * typewriter paint. Streamed turns arrive in 100-500ms slabs (model burst,
96
+ * flush windows, replay polls); revealing characters at an adaptive rate
97
+ * makes the same bytes read as top-tier streaming. The rate scales with the
98
+ * backlog so the reveal never falls behind the stream — it crawls when caught
99
+ * up and sprints when a burst lands (e.g. a reasoning summary arriving all at
100
+ * once still *types out* instead of popping in).
101
+ */
102
+ interface SmoothRevealOptions {
103
+ /** Baseline reveal rate when nearly caught up. Default 90 chars/s. */
104
+ baseCharsPerSecond?: number;
105
+ /** Extra chars/s per backlog character — the catch-up pressure. Default 5. */
106
+ catchUpPerChar?: number;
107
+ /** Hard ceiling so giant bursts still animate. Default 2400 chars/s. */
108
+ maxCharsPerSecond?: number;
109
+ }
110
+ /** Pure reveal step: how many characters should be visible after `dtMs`.
111
+ * Exposed for tests; the hook is a thin rAF wrapper around it. */
112
+ declare function nextRevealCount(shown: number, targetLength: number, dtMs: number, opts?: SmoothRevealOptions): number;
113
+ /**
114
+ * Animate `target` text into view. While `enabled`, the returned string grows
115
+ * smoothly toward `target` (which may itself keep growing); when `enabled` is
116
+ * false the full text returns immediately (history, completed turns). A
117
+ * target that is not an extension of the revealed prefix (new message) resets
118
+ * the reveal.
119
+ */
120
+ declare function useSmoothText(target: string, enabled: boolean, opts?: SmoothRevealOptions): string;
121
+
93
122
  interface ChatMessageMetrics {
94
123
  modelUsed?: string;
95
124
  promptTokens?: number;
@@ -202,4 +231,4 @@ interface ProposalApprovalHandlers {
202
231
  */
203
232
  declare function ChatMessages({ messages, models, renderMarkdown, renderExtras, userLabel, agentLabel, loading, approval, onToolCallClick, }: ChatMessagesProps): react.JSX.Element;
204
233
 
205
- export { type ChatMessageMetrics, ChatMessages, type ChatMessagesProps, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ConsumeChatStreamResult, EffortPicker, type EffortPickerProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, RunDrillIn, type RunDrillInProps, type StreamChatOptions, type ToolRunRecord, type ToolRunStep, consumeChatStream, dispatchChatStreamLine, formatModelCost, formatTokensPerSecond, pendingApprovalOf, streamChatTurn };
234
+ export { type ChatMessageMetrics, ChatMessages, type ChatMessagesProps, type ChatStreamCallbacks, type ChatStreamToolCall, type ChatStreamToolResult, type ChatToolCallInfo, type ChatUiMessage, type ConsumeChatStreamResult, EffortPicker, type EffortPickerProps, ModelPicker, type ModelPickerProps, type ProposalApprovalHandlers, ProviderLogo, type ProviderLogoProps, RunDrillIn, type RunDrillInProps, type SmoothRevealOptions, type StreamChatOptions, type ToolRunRecord, type ToolRunStep, consumeChatStream, dispatchChatStreamLine, formatModelCost, formatTokensPerSecond, nextRevealCount, pendingApprovalOf, streamChatTurn, useSmoothText };
@@ -1,5 +1,5 @@
1
1
  // src/web-react/index.tsx
2
- import { useEffect, useMemo, useRef, useState } from "react";
2
+ import { useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
3
3
 
4
4
  // src/web-react/provider-logo.tsx
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -41,6 +41,46 @@ function ProviderLogo({ provider, size = 16 }) {
41
41
  ] });
42
42
  }
43
43
 
44
+ // src/web-react/smooth-text.ts
45
+ import { useEffect, useRef, useState } from "react";
46
+ function nextRevealCount(shown, targetLength, dtMs, opts = {}) {
47
+ if (shown >= targetLength) return targetLength;
48
+ const base = opts.baseCharsPerSecond ?? 90;
49
+ const catchUp = opts.catchUpPerChar ?? 5;
50
+ const max = opts.maxCharsPerSecond ?? 2400;
51
+ const backlog = targetLength - shown;
52
+ const rate = Math.min(max, base + backlog * catchUp);
53
+ return Math.min(targetLength, shown + rate * dtMs / 1e3);
54
+ }
55
+ function useSmoothText(target, enabled, opts) {
56
+ const [, force] = useState(0);
57
+ const shownRef = useRef(0);
58
+ const lastTargetRef = useRef("");
59
+ if (!target.startsWith(lastTargetRef.current.slice(0, Math.floor(shownRef.current)))) {
60
+ shownRef.current = 0;
61
+ }
62
+ lastTargetRef.current = target;
63
+ if (!enabled) shownRef.current = target.length;
64
+ useEffect(() => {
65
+ if (!enabled) return;
66
+ let raf = 0;
67
+ let last = null;
68
+ const tick = (t) => {
69
+ const dt = last == null ? 16 : Math.min(t - last, 100);
70
+ last = t;
71
+ const targetLen = lastTargetRef.current.length;
72
+ if (shownRef.current < targetLen) {
73
+ shownRef.current = nextRevealCount(shownRef.current, targetLen, dt, opts);
74
+ force((n) => n + 1);
75
+ }
76
+ raf = requestAnimationFrame(tick);
77
+ };
78
+ raf = requestAnimationFrame(tick);
79
+ return () => cancelAnimationFrame(raf);
80
+ }, [enabled]);
81
+ return target.slice(0, Math.floor(shownRef.current));
82
+ }
83
+
44
84
  // src/web-react/chat-stream.ts
45
85
  function dispatchChatStreamLine(line, cb) {
46
86
  let receivedContent = false;
@@ -181,8 +221,8 @@ function SparkleGlyph({ className }) {
181
221
  return /* @__PURE__ */ jsx2("svg", { className, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "M12 3v3m0 12v3M3 12h3m12 0h3M5.6 5.6l2.1 2.1m8.6 8.6 2.1 2.1m0-12.8-2.1 2.1M7.7 16.3l-2.1 2.1" }) });
182
222
  }
183
223
  function useClickOutside(onOutside) {
184
- const ref = useRef(null);
185
- useEffect(() => {
224
+ const ref = useRef2(null);
225
+ useEffect2(() => {
186
226
  function handler(e) {
187
227
  if (ref.current && !ref.current.contains(e.target)) onOutside();
188
228
  }
@@ -246,11 +286,11 @@ function ModelRow({
246
286
  );
247
287
  }
248
288
  function ModelPicker({ value, onChange, models, loading, renderProviderBadge, recommendedLabel = "Recommended" }) {
249
- const [open, setOpen] = useState(false);
250
- const [query, setQuery] = useState("");
289
+ const [open, setOpen] = useState2(false);
290
+ const [query, setQuery] = useState2("");
251
291
  const containerRef = useClickOutside(() => setOpen(false));
252
- const inputRef = useRef(null);
253
- useEffect(() => {
292
+ const inputRef = useRef2(null);
293
+ useEffect2(() => {
254
294
  if (open) inputRef.current?.focus();
255
295
  }, [open]);
256
296
  const selected = models.find((m) => m.id === value);
@@ -333,7 +373,7 @@ var EFFORT_LEVELS = [
333
373
  { id: "high", label: "High" }
334
374
  ];
335
375
  function EffortPicker({ value, onChange }) {
336
- const [open, setOpen] = useState(false);
376
+ const [open, setOpen] = useState2(false);
337
377
  const containerRef = useClickOutside(() => setOpen(false));
338
378
  const selected = EFFORT_LEVELS.find((l) => l.id === value) ?? EFFORT_LEVELS[2];
339
379
  return /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative inline-flex", children: [
@@ -466,6 +506,64 @@ function ToolChips({
466
506
  );
467
507
  }) });
468
508
  }
509
+ function AssistantMessage({
510
+ msg,
511
+ streaming,
512
+ models,
513
+ agentLabel,
514
+ renderBody,
515
+ approval,
516
+ onToolCallClick,
517
+ renderExtras
518
+ }) {
519
+ const content = useSmoothText(msg.content, streaming);
520
+ const reasoning = useSmoothText(msg.reasoning ?? "", streaming);
521
+ const reasoningScrollRef = useRef2(null);
522
+ useEffect2(() => {
523
+ const el = reasoningScrollRef.current;
524
+ if (el && streaming && !content) el.scrollTop = el.scrollHeight;
525
+ }, [reasoning, streaming, content]);
526
+ return /* @__PURE__ */ jsxs2("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
527
+ /* @__PURE__ */ jsxs2("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground/60", children: [
528
+ /* @__PURE__ */ jsx2("span", { className: "font-semibold uppercase", children: agentLabel }),
529
+ msg.modelUsed && /* @__PURE__ */ jsx2("span", { className: "font-mono normal-case", children: msg.modelUsed }),
530
+ formatTokensPerSecond(msg) && /* @__PURE__ */ jsx2("span", { children: formatTokensPerSecond(msg) }),
531
+ formatModelCost(msg, models) && /* @__PURE__ */ jsx2("span", { children: formatModelCost(msg, models) })
532
+ ] }),
533
+ reasoning && /* @__PURE__ */ jsxs2("details", { className: "mb-2 rounded-md border border-border/40 bg-muted/30 px-3 py-2", open: !content, children: [
534
+ /* @__PURE__ */ jsxs2("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: [
535
+ content ? "Thinking\u2026" : "Thinking",
536
+ !content && /* @__PURE__ */ jsx2("span", { className: "ml-1 inline-block animate-pulse", children: "\u25CF" })
537
+ ] }),
538
+ /* @__PURE__ */ jsx2("div", { ref: reasoningScrollRef, className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-sm text-muted-foreground/80", children: reasoning })
539
+ ] }),
540
+ /* @__PURE__ */ jsx2("div", { className: "text-base leading-[1.75]", children: renderBody(content) }),
541
+ msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx2(
542
+ ToolChips,
543
+ {
544
+ toolCalls: msg.toolCalls,
545
+ approval,
546
+ onClick: onToolCallClick ? (tc) => onToolCallClick(tc, msg) : void 0
547
+ }
548
+ ),
549
+ renderExtras?.(msg)
550
+ ] });
551
+ }
552
+ function ThinkingRow({ agentLabel }) {
553
+ const [seconds, setSeconds] = useState2(0);
554
+ useEffect2(() => {
555
+ const id = setInterval(() => setSeconds((s) => s + 1), 1e3);
556
+ return () => clearInterval(id);
557
+ }, []);
558
+ return /* @__PURE__ */ jsxs2("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
559
+ /* @__PURE__ */ jsx2("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: agentLabel }),
560
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
561
+ /* @__PURE__ */ jsx2("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
562
+ "Thinking",
563
+ seconds >= 3 ? ` \xB7 ${seconds}s` : "..."
564
+ ] })
565
+ ] });
566
+ }
469
567
  function ChatMessages({
470
568
  messages,
471
569
  models = [],
@@ -484,46 +582,22 @@ function ChatMessages({
484
582
  (msg) => msg.role === "user" ? /* @__PURE__ */ jsx2("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: /* @__PURE__ */ jsxs2("div", { className: "ml-auto w-fit max-w-[85%]", children: [
485
583
  /* @__PURE__ */ jsx2("p", { className: "mb-1 text-right text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: userLabel }),
486
584
  /* @__PURE__ */ jsx2("div", { className: "rounded-2xl rounded-tr-md bg-primary/10 px-4 py-2.5 text-base leading-relaxed", children: /* @__PURE__ */ jsx2("p", { className: "whitespace-pre-wrap", children: msg.content }) })
487
- ] }) }, msg.id) : /* @__PURE__ */ jsxs2("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
488
- /* @__PURE__ */ jsxs2("div", { className: "mb-1 flex items-baseline gap-2 text-[11px] tracking-wide text-muted-foreground/60", children: [
489
- /* @__PURE__ */ jsx2("span", { className: "font-semibold uppercase", children: agentLabel }),
490
- msg.modelUsed && /* @__PURE__ */ jsx2("span", { className: "font-mono normal-case", children: msg.modelUsed }),
491
- formatTokensPerSecond(msg) && /* @__PURE__ */ jsx2("span", { children: formatTokensPerSecond(msg) }),
492
- formatModelCost(msg, models) && /* @__PURE__ */ jsx2("span", { children: formatModelCost(msg, models) })
493
- ] }),
494
- msg.reasoning && /* @__PURE__ */ jsxs2(
495
- "details",
496
- {
497
- className: "mb-2 rounded-md border border-border/40 bg-muted/30 px-3 py-2",
498
- open: !msg.content,
499
- children: [
500
- /* @__PURE__ */ jsxs2("summary", { className: "cursor-pointer select-none text-xs font-medium text-muted-foreground", children: [
501
- msg.content ? "Thinking\u2026" : "Thinking",
502
- !msg.content && /* @__PURE__ */ jsx2("span", { className: "ml-1 inline-block animate-pulse", children: "\u25CF" })
503
- ] }),
504
- /* @__PURE__ */ jsx2("div", { className: "mt-2 max-h-48 overflow-y-auto whitespace-pre-wrap text-sm text-muted-foreground/80", children: msg.reasoning })
505
- ]
506
- }
507
- ),
508
- /* @__PURE__ */ jsx2("div", { className: "text-base leading-[1.75]", children: renderBody(msg.content) }),
509
- msg.toolCalls && msg.toolCalls.length > 0 && /* @__PURE__ */ jsx2(
510
- ToolChips,
511
- {
512
- toolCalls: msg.toolCalls,
513
- approval,
514
- onClick: onToolCallClick ? (tc) => onToolCallClick(tc, msg) : void 0
515
- }
516
- ),
517
- renderExtras?.(msg)
518
- ] }, msg.id)
585
+ ] }) }, msg.id) : /* @__PURE__ */ jsx2(
586
+ AssistantMessage,
587
+ {
588
+ msg,
589
+ streaming: !!loading && msg.id === messages[messages.length - 1]?.id,
590
+ models,
591
+ agentLabel,
592
+ renderBody,
593
+ approval,
594
+ onToolCallClick,
595
+ renderExtras
596
+ },
597
+ msg.id
598
+ )
519
599
  ),
520
- loading && lastIsUser && /* @__PURE__ */ jsxs2("div", { className: "mx-auto w-full max-w-3xl px-6 py-3", children: [
521
- /* @__PURE__ */ jsx2("p", { className: "mb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground/60", children: agentLabel }),
522
- /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 text-base text-muted-foreground", children: [
523
- /* @__PURE__ */ jsx2("svg", { className: "h-4 w-4 animate-spin", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": true, children: /* @__PURE__ */ jsx2("path", { d: "M21 12a9 9 0 1 1-6.219-8.56", strokeLinecap: "round" }) }),
524
- "Thinking..."
525
- ] })
526
- ] })
600
+ loading && lastIsUser && /* @__PURE__ */ jsx2(ThinkingRow, { agentLabel })
527
601
  ] });
528
602
  }
529
603
  export {
@@ -536,7 +610,9 @@ export {
536
610
  dispatchChatStreamLine,
537
611
  formatModelCost,
538
612
  formatTokensPerSecond,
613
+ nextRevealCount,
539
614
  pendingApprovalOf,
540
- streamChatTurn
615
+ streamChatTurn,
616
+ useSmoothText
541
617
  };
542
618
  //# sourceMappingURL=index.js.map