Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
81 lines
2.6 KiB
TypeScript
81 lines
2.6 KiB
TypeScript
export function objectRecord(value: unknown): Record<string, unknown> | null {
|
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
? (value as Record<string, unknown>)
|
|
: null;
|
|
}
|
|
|
|
export function numberValue(value: unknown): number | null {
|
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
return value;
|
|
}
|
|
if (typeof value === "string" && value.trim() !== "") {
|
|
const parsed = Number(value);
|
|
return Number.isFinite(parsed) ? parsed : null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function stringValue(value: unknown): string {
|
|
return typeof value === "string" ? value : "";
|
|
}
|
|
|
|
export function useStableEventCallback<Args extends unknown[], Result>(
|
|
callback: (...args: Args) => Result
|
|
): (...args: Args) => Result {
|
|
const callbackRef = useRef(callback);
|
|
useLayoutEffect(() => {
|
|
callbackRef.current = callback;
|
|
}, [callback]);
|
|
return useCallback((...args: Args) => callbackRef.current(...args), []);
|
|
}
|
|
|
|
export function useOptionalStableEventCallback<Args extends unknown[], Result>(
|
|
callback: ((...args: Args) => Result) | null | undefined
|
|
): ((...args: Args) => Result) | undefined {
|
|
const callbackRef = useRef(callback);
|
|
useLayoutEffect(() => {
|
|
callbackRef.current = callback;
|
|
}, [callback]);
|
|
return useMemo(() => {
|
|
if (callback == null) {
|
|
return undefined;
|
|
}
|
|
return (...args: Args) => callbackRef.current?.(...args) as Result;
|
|
}, [callback != null]);
|
|
}
|
|
import type { UiLanguage } from "../../../contexts/settings/domain/agentSettings";
|
|
import { resolveAgentGUIConversationDisplayTitle } from "../model/agentGuiProviderIdentity";
|
|
import type { AgentGUINodeViewModel } from "../model/agentGuiNodeTypes";
|
|
import type { AgentGUIViewLabels } from "../AgentGUINodeView";
|
|
import type { WorkspaceFileReferenceCopy } from "@tutti-os/workspace-file-reference/contracts";
|
|
|
|
export const fallbackWorkspaceFileReferenceCopy: WorkspaceFileReferenceCopy = {
|
|
t(key, values) {
|
|
return values ? `${key}:${JSON.stringify(values)}` : key;
|
|
}
|
|
};
|
|
|
|
export function agentGuiPerfNowMs(): number {
|
|
return globalThis.performance?.now?.() ?? Date.now();
|
|
}
|
|
|
|
export function roundAgentGuiPerfMs(value: number): number {
|
|
return Math.round(value * 100) / 100;
|
|
}
|
|
|
|
export function conversationPlainTitle(
|
|
conversation: Pick<
|
|
AgentGUINodeViewModel["rail"]["conversations"][number],
|
|
"title" | "titleFallback"
|
|
>,
|
|
labels: Pick<AgentGUIViewLabels, "untitledConversationTitle">,
|
|
uiLanguage: UiLanguage
|
|
): string {
|
|
void uiLanguage;
|
|
return resolveAgentGUIConversationDisplayTitle(
|
|
conversation,
|
|
labels.untitledConversationTitle
|
|
);
|
|
}
|
|
import { useCallback, useLayoutEffect, useMemo, useRef } from "react";
|