@hashgraphonline/conversational-agent
Version:
Hashgraph Online conversational AI agent implementing HCS-10 communication, HCS-2 registries, and content inscription on Hedera. https://hol.org
173 lines (151 loc) • 4.69 kB
text/typescript
import { Bee, PostageBatch } from "@ethersphere/bee-js";
import { PostageBatchCurated, PostageBatchSummary } from "./model";
import { SwarmConfig } from "./config";
import { DEFAULT_GATEWAY_BATCH_ID, NOT_FOUND_STATUS } from "./constants";
export interface ToolResponse {
[x: string]: unknown;
tools?: { [x: string]: unknown; name: string /* other properties */ };
_meta?: { [x: string]: unknown };
}
export function hexToBytes(hex: string): Uint8Array {
const bytes = new Uint8Array(hex.length / 2);
for (let i = 0; i < hex.length; i += 2) {
bytes[i / 2] = parseInt(hex.slice(i, i + 2), 16);
}
return bytes;
}
export const getBatchSummary = (
batch: PostageBatch | PostageBatchCurated
): PostageBatchSummary => ({
stampID:
typeof batch.batchID === "string" ? batch.batchID : batch.batchID.toHex(),
usage: batch.usageText,
capacity: `${batch.remainingSize.toFormattedString()} remaining out of ${batch.size.toFormattedString()}`,
immutable: batch.immutableFlag,
ttl: `${batch.duration.represent()} (${batch.duration
.toEndDate()
.toDateString()})`,
});
export const getResponseWithStructuredContent = <T>(data: T): ToolResponse => ({
content: [
{
type: "text",
text: JSON.stringify(data, null, 2),
},
],
structuredContent: data,
});
export const errorHasStatus = (error: unknown, status: number) => {
if (typeof error === "object" && error !== null && "status" in error) {
return error.status === status;
}
return false;
};
export const getErrorMessage = (error: unknown) => {
if (
typeof error === "object" &&
error !== null &&
"responseBody" in error &&
typeof error.responseBody === "object" &&
error.responseBody !== null &&
"message" in error.responseBody
) {
return error.responseBody.message as string;
}
return "";
};
export const runWithTimeout = async <T>(
asyncAction: Promise<T>,
timeout: number
): Promise<[unknown, boolean]> => {
let hasTimedOut = false;
const timeoutPromise = new Promise((resolve) =>
setTimeout(() => {
hasTimedOut = true;
resolve(true);
}, timeout)
);
const response = await Promise.race([asyncAction, timeoutPromise]);
return [response, hasTimedOut];
};
export const getUploadPostageBatchId = async (
argsPostageBatchId: string | undefined,
bee: Bee,
config: SwarmConfig,
): Promise<string> => {
let postageBatchId = argsPostageBatchId;
const autoAssignStamp = config.autoAssignStamp ?? true;
let maxRemainingSize = 0;
if (!postageBatchId && !autoAssignStamp) {
throw new Error('No postageBatchId was provided. Please repeat the prompt and also specify the usable postage batch id.');
} else if (!postageBatchId) {
try {
const rawPostageBatches = await bee.getPostageBatches();
rawPostageBatches.forEach((batch) => {
if (!batch.usable) {
return;
}
const remainingSize = batch.remainingSize.toBytes();
if (remainingSize > maxRemainingSize) {
maxRemainingSize = remainingSize;
postageBatchId = batch.batchID.toHex();
}
});
} catch (error) {
if (errorHasStatus(error, NOT_FOUND_STATUS)) {
postageBatchId = DEFAULT_GATEWAY_BATCH_ID;
} else {
throw new Error('Retrieval of postage batches failed.');
}
}
}
if (!postageBatchId) {
throw new Error('There is no usable postage batch with capacity.');
}
return postageBatchId!;
};
const dateUnits: Record<string, number | undefined> = {
ms: 1,
milli: 1,
millis: 1,
millisecond: 1,
milliseconds: 1,
s: 1000,
sec: 1000,
second: 1000,
seconds: 1000,
m: 60_000,
min: 60_000,
minute: 60_000,
minutes: 60_000,
h: 3_600_000,
hour: 3_600_000,
hours: 3_600_000,
d: 86_400_000,
day: 86_400_000,
days: 86_400_000,
w: 604_800_000,
week: 604_800_000,
weeks: 604_800_000,
month: 2_592_000_000,
months: 2_592_000_000,
y: 31_536_000_000,
year: 31_536_000_000,
years: 31_536_000_000,
};
// From bee.js
export function makeDate(numberWithUnit: string): number {
const number = parseFloat(numberWithUnit);
if (isNaN(number)) {
throw Error("makeDate got NaN for input");
}
const unit = numberWithUnit
.replace(/^-?[0-9.]+/, "")
.trim()
.toLowerCase();
const multiplier = dateUnits[unit];
if (!multiplier) {
throw Error(`Unknown unit: "${unit}"`);
}
return number * multiplier;
}