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

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,59 @@
/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import {
buildToolSubBlockId,
isSyntheticToolSubBlockId,
resolveToolParamSync,
} from '@/lib/workflows/tool-input/synthetic-subblocks'
describe('buildToolSubBlockId', () => {
it('composes the synthetic id from aggregate id, tool index, and param id', () => {
expect(buildToolSubBlockId('tools', 0, 'knowledgeBaseSelector')).toBe(
'tools-tool-0-knowledgeBaseSelector'
)
expect(buildToolSubBlockId('tools', 3, 'credential')).toBe('tools-tool-3-credential')
})
it('produces ids recognized by isSyntheticToolSubBlockId', () => {
expect(isSyntheticToolSubBlockId(buildToolSubBlockId('tools', 0, 'file'))).toBe(true)
expect(isSyntheticToolSubBlockId(buildToolSubBlockId('tools', 12, 'documentTags'))).toBe(true)
})
})
describe('isSyntheticToolSubBlockId', () => {
it('returns false for real subblock ids', () => {
expect(isSyntheticToolSubBlockId('tools')).toBe(false)
expect(isSyntheticToolSubBlockId('model')).toBe(false)
expect(isSyntheticToolSubBlockId('knowledgeBaseSelector')).toBe(false)
expect(isSyntheticToolSubBlockId('tools-credential')).toBe(false)
})
})
describe('resolveToolParamSync', () => {
it('re-projects a removed key instead of clearing params', () => {
expect(resolveToolParamSync(undefined, 'kb-123')).toEqual({ action: 'reproject' })
})
it('mirrors a user clear as an empty string', () => {
expect(resolveToolParamSync('', 'kb-123')).toEqual({ action: 'mirror', value: '' })
expect(resolveToolParamSync(null, 'kb-123')).toEqual({ action: 'mirror', value: '' })
})
it('mirrors a changed value', () => {
expect(resolveToolParamSync('kb-456', 'kb-123')).toEqual({ action: 'mirror', value: 'kb-456' })
})
it('is a noop when the value already matches the synced value', () => {
expect(resolveToolParamSync('kb-123', 'kb-123')).toEqual({ action: 'noop' })
})
it('stringifies object values for object-typed params', () => {
expect(resolveToolParamSync({ name: 'a.pdf' }, '{"name":"a.pdf"}')).toEqual({ action: 'noop' })
expect(resolveToolParamSync({ name: 'b.pdf' }, '{"name":"a.pdf"}')).toEqual({
action: 'mirror',
value: '{"name":"b.pdf"}',
})
})
})
@@ -0,0 +1,60 @@
const TOOL_SUBBLOCK_INFIX = '-tool-'
const SYNTHETIC_TOOL_SUBBLOCK_RE = new RegExp(`${TOOL_SUBBLOCK_INFIX}\\d+-`)
/**
* Builds the synthetic subblock id used to render a block-based tool's param
* inside a tool row.
*
* The id follows `{subBlockId}-tool-{index}-{paramId}` and is an ephemeral,
* client-only projection key for the value held canonically at
* `tool.params[paramId]` in the aggregate `tool-input` subblock.
*/
export function buildToolSubBlockId(
aggregateSubBlockId: string,
toolIndex: number,
paramId: string
): string {
return `${aggregateSubBlockId}${TOOL_SUBBLOCK_INFIX}${toolIndex}-${paramId}`
}
/**
* Returns true for ToolSubBlockRenderer mirror subblocks produced by
* {@link buildToolSubBlockId}. These duplicate values already stored in the
* aggregate `tool-input` subblock and must never be persisted or compared.
*/
export function isSyntheticToolSubBlockId(subBlockId: string): boolean {
return SYNTHETIC_TOOL_SUBBLOCK_RE.test(subBlockId)
}
type ToolParamSyncAction =
| { action: 'noop' }
| { action: 'reproject' }
| { action: 'mirror'; value: string }
/**
* Reconciles a change to a synthetic tool subblock value with the canonical
* `tool.params`. The synthetic key is a projection of `tool.params`, so:
*
* - `undefined` means the key was dropped by a wholesale store replace — restore
* it from `tool.params` ({@link ToolParamSyncAction.action} `reproject`). A
* removal is never a user clear.
* - any defined value (including `''` or `null`, both meaning "cleared by the
* user") is a genuine edit to write back (`mirror`).
* - a value already matching `syncedValue` needs no work (`noop`).
*/
export function resolveToolParamSync(
storeValue: unknown,
syncedValue: string | null
): ToolParamSyncAction {
if (storeValue === undefined) return { action: 'reproject' }
const stringified =
storeValue === null
? ''
: typeof storeValue === 'string'
? storeValue
: JSON.stringify(storeValue)
if (stringified === syncedValue) return { action: 'noop' }
return { action: 'mirror', value: stringified }
}
@@ -0,0 +1,70 @@
interface StoredToolSchema {
description?: string
properties?: Record<string, unknown>
required?: string[]
function?: {
name?: string
parameters?: {
properties?: Record<string, unknown>
required?: string[]
}
}
}
/**
* Represents a tool selected and configured in a workflow tool-input field.
*/
export interface StoredTool {
type: string
title?: string
toolId?: string
params?: Record<string, string>
isExpanded?: boolean
customToolId?: string
schema?: StoredToolSchema
code?: string
operation?: string
usageControl?: 'auto' | 'force' | 'none'
}
export interface ParsedStoredTool extends Omit<StoredTool, 'params'> {
params?: Record<string, unknown>
}
export function parseStoredToolInputValue(value: unknown): ParsedStoredTool[] {
if (!Array.isArray(value)) return []
return value.flatMap((tool) => {
if (!tool || typeof tool !== 'object' || Array.isArray(tool)) return []
const record = tool as Record<string, unknown>
if (typeof record.type !== 'string') return []
const params =
record.params && typeof record.params === 'object' && !Array.isArray(record.params)
? (record.params as Record<string, unknown>)
: undefined
return [
{
type: record.type,
title: typeof record.title === 'string' ? record.title : undefined,
toolId: typeof record.toolId === 'string' ? record.toolId : undefined,
operation: typeof record.operation === 'string' ? record.operation : undefined,
params,
customToolId: typeof record.customToolId === 'string' ? record.customToolId : undefined,
code: typeof record.code === 'string' ? record.code : undefined,
usageControl:
record.usageControl === 'auto' ||
record.usageControl === 'force' ||
record.usageControl === 'none'
? record.usageControl
: undefined,
isExpanded: typeof record.isExpanded === 'boolean' ? record.isExpanded : undefined,
schema:
record.schema && typeof record.schema === 'object' && !Array.isArray(record.schema)
? (record.schema as StoredToolSchema)
: undefined,
},
]
})
}