chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { formatGeneratedSource } from './format-generated-source'
|
||||
|
||||
/**
|
||||
* Generate `apps/sim/lib/copilot/generated/trace-attribute-values-v1.ts`
|
||||
* from the Go-side `contracts/trace-attribute-values-v1.schema.json`
|
||||
* contract.
|
||||
*
|
||||
* Unlike span-names / attribute-keys / event-names (each of which is a
|
||||
* single enum), this contract carries MULTIPLE enums — one per span
|
||||
* attribute whose value set is closed. The schema's `$defs` holds one
|
||||
* definition per enum (e.g. `CopilotRequestCancelReason`,
|
||||
* `CopilotAbortOutcome`, …). For each $def we emit a TS `as const`
|
||||
* object named after the Go type, so call sites read as:
|
||||
*
|
||||
* span.setAttribute(
|
||||
* TraceAttr.CopilotRequestCancelReason,
|
||||
* CopilotRequestCancelReason.ExplicitStop,
|
||||
* )
|
||||
*
|
||||
* Skipped $defs: anything that doesn't have a string-only `enum`
|
||||
* array. That filters out wrapper structs the reflector adds
|
||||
* incidentally (e.g. `TraceAttributeValuesV1AllDefs`).
|
||||
*/
|
||||
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
|
||||
const ROOT = resolve(SCRIPT_DIR, '..')
|
||||
const DEFAULT_CONTRACT_PATH = resolve(
|
||||
ROOT,
|
||||
'../copilot/copilot/contracts/trace-attribute-values-v1.schema.json'
|
||||
)
|
||||
const OUTPUT_PATH = resolve(ROOT, 'apps/sim/lib/copilot/generated/trace-attribute-values-v1.ts')
|
||||
|
||||
interface ExtractedEnum {
|
||||
/** The Go type name — becomes the TS const + type name. */
|
||||
name: string
|
||||
/** The value strings, sorted for diff stability. */
|
||||
values: string[]
|
||||
}
|
||||
|
||||
function extractEnums(schema: Record<string, unknown>): ExtractedEnum[] {
|
||||
const defs = (schema.$defs ?? {}) as Record<string, unknown>
|
||||
const out: ExtractedEnum[] = []
|
||||
for (const [name, def] of Object.entries(defs)) {
|
||||
if (!def || typeof def !== 'object') continue
|
||||
const enumValues = (def as Record<string, unknown>).enum
|
||||
if (!Array.isArray(enumValues)) continue
|
||||
if (!enumValues.every((v) => typeof v === 'string')) continue
|
||||
out.push({ name, values: (enumValues as string[]).slice().sort() })
|
||||
}
|
||||
out.sort((a, b) => a.name.localeCompare(b.name))
|
||||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* PascalCase identifier for a wire enum value. Mirrors the algorithm
|
||||
* used by the span-names + attribute-keys scripts, so
|
||||
* `explicit_stop` -> `ExplicitStop`, matching what a reader would
|
||||
* guess from Go's exported constants.
|
||||
*/
|
||||
function toValueIdent(value: string): string {
|
||||
const parts = value.split(/[^A-Za-z0-9]+/).filter(Boolean)
|
||||
if (parts.length === 0) {
|
||||
throw new Error(`Cannot derive identifier for enum value: ${value}`)
|
||||
}
|
||||
const ident = parts.map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()).join('')
|
||||
if (/^[0-9]/.test(ident)) {
|
||||
throw new Error(`Derived identifier "${ident}" for value "${value}" starts with a digit`)
|
||||
}
|
||||
return ident
|
||||
}
|
||||
|
||||
function renderEnum(e: ExtractedEnum): string {
|
||||
const seen = new Map<string, string>()
|
||||
const lines = e.values.map((v) => {
|
||||
const ident = toValueIdent(v)
|
||||
const prev = seen.get(ident)
|
||||
if (prev && prev !== v) {
|
||||
throw new Error(
|
||||
`Enum ${e.name}: identifier collision — "${prev}" and "${v}" both map to "${ident}"`
|
||||
)
|
||||
}
|
||||
seen.set(ident, v)
|
||||
return ` ${ident}: ${JSON.stringify(v)},`
|
||||
})
|
||||
|
||||
return `export const ${e.name} = {
|
||||
${lines.join('\n')}
|
||||
} as const;
|
||||
|
||||
export type ${e.name}Key = keyof typeof ${e.name};
|
||||
export type ${e.name}Value = (typeof ${e.name})[${e.name}Key];`
|
||||
}
|
||||
|
||||
function render(enums: ExtractedEnum[]): string {
|
||||
const body = enums.map(renderEnum).join('\n\n')
|
||||
return `// AUTO-GENERATED FILE. DO NOT EDIT.
|
||||
//
|
||||
// Source: copilot/copilot/contracts/trace-attribute-values-v1.schema.json
|
||||
// Regenerate with: bun run trace-attribute-values-contract:generate
|
||||
//
|
||||
// Canonical closed-set value vocabularies for mothership OTel
|
||||
// attributes. Call sites should reference e.g.
|
||||
// \`CopilotRequestCancelReason.ExplicitStop\` rather than the raw
|
||||
// string literal, so typos become compile errors and the Go contract
|
||||
// remains the single source of truth.
|
||||
|
||||
${body}
|
||||
`
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const checkOnly = process.argv.includes('--check')
|
||||
const inputArg = process.argv.find((a) => a.startsWith('--input='))
|
||||
const inputPath = inputArg
|
||||
? resolve(ROOT, inputArg.slice('--input='.length))
|
||||
: DEFAULT_CONTRACT_PATH
|
||||
|
||||
const raw = await readFile(inputPath, 'utf8')
|
||||
const schema = JSON.parse(raw)
|
||||
const enums = extractEnums(schema)
|
||||
if (enums.length === 0) {
|
||||
throw new Error(
|
||||
'No enum $defs found in trace-attribute-values-v1.schema.json — did you add the Go type to TraceAttributeValuesV1AllDefs?'
|
||||
)
|
||||
}
|
||||
const rendered = formatGeneratedSource(render(enums), OUTPUT_PATH, ROOT)
|
||||
|
||||
if (checkOnly) {
|
||||
const existing = await readFile(OUTPUT_PATH, 'utf8').catch(() => null)
|
||||
if (existing !== rendered) {
|
||||
throw new Error(
|
||||
'Generated trace attribute values contract is stale. Run: bun run trace-attribute-values-contract:generate'
|
||||
)
|
||||
}
|
||||
console.log('Trace attribute values contract is up to date.')
|
||||
return
|
||||
}
|
||||
|
||||
await mkdir(dirname(OUTPUT_PATH), { recursive: true })
|
||||
await writeFile(OUTPUT_PATH, rendered, 'utf8')
|
||||
console.log(`Generated trace attribute values types -> ${OUTPUT_PATH}`)
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user