| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- 'use strict';
- const crypto = require('crypto');
- const fs = require('fs');
- const path = require('path');
- const MAX_LABEL = 120;
- const ID_RE = /^[A-Za-z0-9._:-]{1,120}$/;
- function cleanLabel(value, fallback = '') {
- const text = String(value == null ? '' : value).trim().replace(/[\r\n\t]+/g, ' ');
- return text.slice(0, MAX_LABEL) || fallback;
- }
- function newId(prefix = '') {
- const id = crypto.randomUUID();
- return prefix ? `${cleanLabel(prefix).replace(/[^A-Za-z0-9_-]/g, '')}_${id}` : id;
- }
- function validId(value) {
- return ID_RE.test(String(value || '').trim());
- }
- function createUsageContext(input = {}) {
- const usageTraceId = validId(input.usageTraceId) ? String(input.usageTraceId).trim() : newId('usage');
- const reportId = input.reportId == null || input.reportId === ''
- ? null
- : (validId(input.reportId) ? String(input.reportId).trim() : newId('report'));
- return {
- usageTraceId,
- reportId,
- skillId: cleanLabel(input.skillId, 'voc-api-catalog'),
- workflowType: cleanLabel(input.workflowType, 'voc_custom_workflow'),
- title: cleanLabel(input.title || input.task),
- clientId: cleanLabel(input.clientId),
- stepId: cleanLabel(input.stepId),
- budgetLimitCny: Number.isFinite(Number(input.budgetLimitCny ?? input.budgetCny))
- ? Math.max(0, Number(input.budgetLimitCny ?? input.budgetCny))
- : null,
- pricingVersion: cleanLabel(input.pricingVersion),
- createdAt: input.createdAt || new Date().toISOString()
- };
- }
- function createStepContext(context, stepId, extra = {}) {
- const base = createUsageContext({ ...context, stepId });
- return {
- ...base,
- requestId: validId(extra.requestId) ? String(extra.requestId).trim() : newId('request'),
- ...(extra.entityId ? { entityId: cleanLabel(extra.entityId) } : {}),
- ...(extra.batchIndex !== undefined ? { batchIndex: Number(extra.batchIndex) || 0 } : {})
- };
- }
- function usageHeaders(context = {}) {
- const headers = {};
- const values = {
- 'X-Fmode-Usage-Trace-Id': context.usageTraceId,
- 'X-Fmode-Report-Id': context.reportId,
- 'X-Fmode-Skill-Id': context.skillId,
- 'X-Fmode-Workflow-Type': context.workflowType,
- 'X-Fmode-Step-Id': context.stepId,
- 'X-Fmode-Client-Id': context.clientId,
- 'X-Fmode-Request-Id': context.requestId
- };
- for (const [name, value] of Object.entries(values)) {
- if (value && validId(value)) headers[name] = String(value);
- }
- return headers;
- }
- function contextForTool(input = {}) {
- return createUsageContext({
- ...input,
- budgetLimitCny: input.budgetLimitCny ?? input.budgetCny
- });
- }
- function writeUsageContext(context, outputDir) {
- if (!outputDir) return null;
- const dir = path.resolve(String(outputDir));
- fs.mkdirSync(dir, { recursive: true });
- const filePath = path.join(dir, 'usage-context.json');
- fs.writeFileSync(filePath, JSON.stringify(context, null, 2));
- return filePath;
- }
- module.exports = {
- MAX_LABEL,
- cleanLabel,
- newId,
- validId,
- createUsageContext,
- createStepContext,
- contextForTool,
- usageHeaders,
- writeUsageContext
- };
|