mirror of
https://github.com/openai/harmony.git
synced 2025-08-22 16:17:08 -04:00
update harmony demo
This commit is contained in:
parent
52176bfbec
commit
9b2dd0a2bf
9 changed files with 1095 additions and 66 deletions
370
demo/harmony-demo/package-lock.json
generated
370
demo/harmony-demo/package-lock.json
generated
|
@ -12,8 +12,11 @@
|
|||
"@openai/harmony": "file:../../javascript",
|
||||
"@radix-ui/react-collapsible": "^1.1.11",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-popover": "^1.1.14",
|
||||
"@radix-ui/react-select": "^2.2.5",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-switch": "^1.2.5",
|
||||
"@radix-ui/react-tabs": "^1.1.12",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@tanstack/react-query": "^5.83.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
|
@ -721,6 +724,12 @@
|
|||
"resolved": "../../javascript",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@radix-ui/number": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
|
||||
"integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
|
||||
|
@ -780,6 +789,32 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-collection": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
|
||||
"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-slot": "1.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-compose-refs": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||
|
@ -810,6 +845,21 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-direction": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
|
||||
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
|
||||
|
@ -837,6 +887,46 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-guards": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz",
|
||||
"integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-focus-scope": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
|
||||
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-id": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
|
||||
|
@ -878,6 +968,43 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popover": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz",
|
||||
"integrity": "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.2",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.10",
|
||||
"@radix-ui/react-focus-guards": "1.1.2",
|
||||
"@radix-ui/react-focus-scope": "1.1.7",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-popper": "1.2.7",
|
||||
"@radix-ui/react-portal": "1.1.9",
|
||||
"@radix-ui/react-presence": "1.1.4",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-slot": "1.2.3",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz",
|
||||
|
@ -981,6 +1108,80 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-roving-focus": {
|
||||
"version": "1.1.10",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz",
|
||||
"integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.2",
|
||||
"@radix-ui/react-collection": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-direction": "1.1.1",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz",
|
||||
"integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/number": "1.1.1",
|
||||
"@radix-ui/primitive": "1.1.2",
|
||||
"@radix-ui/react-collection": "1.1.7",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-direction": "1.1.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.10",
|
||||
"@radix-ui/react-focus-guards": "1.1.2",
|
||||
"@radix-ui/react-focus-scope": "1.1.7",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-popper": "1.2.7",
|
||||
"@radix-ui/react-portal": "1.1.9",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-slot": "1.2.3",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.1",
|
||||
"@radix-ui/react-use-previous": "1.1.1",
|
||||
"@radix-ui/react-visually-hidden": "1.2.3",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||
|
@ -1028,6 +1229,36 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tabs": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.12.tgz",
|
||||
"integrity": "sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-direction": "1.1.1",
|
||||
"@radix-ui/react-id": "1.1.1",
|
||||
"@radix-ui/react-presence": "1.1.4",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-roving-focus": "1.1.10",
|
||||
"@radix-ui/react-use-controllable-state": "1.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-tooltip": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz",
|
||||
|
@ -1568,6 +1799,18 @@
|
|||
"@types/react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/aria-hidden": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
||||
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001727",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
|
||||
|
@ -1687,6 +1930,12 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node-es": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.18.2",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
|
||||
|
@ -1701,6 +1950,15 @@
|
|||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-nonce": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
||||
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
|
@ -2176,6 +2434,75 @@
|
|||
"react": "^19.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
|
||||
"integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-remove-scroll-bar": "^2.3.7",
|
||||
"react-style-singleton": "^2.2.3",
|
||||
"tslib": "^2.1.0",
|
||||
"use-callback-ref": "^1.3.3",
|
||||
"use-sidecar": "^1.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll-bar": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
||||
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-style-singleton": "^2.2.2",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-style-singleton": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
||||
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-nonce": "^1.0.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.26.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
|
||||
|
@ -2362,6 +2689,49 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/use-callback-ref": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
||||
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-sidecar": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
|
||||
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"detect-node-es": "^1.1.0",
|
||||
"tslib": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||
|
|
|
@ -7,14 +7,18 @@
|
|||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"build:wasm": "cd ../../ && wasm-pack build --target web --out-dir javascript/dist/web --features wasm-binding --no-default-features && wasm-pack build --target nodejs --out-dir javascript/dist/node --features wasm-binding --no-default-features"
|
||||
},
|
||||
"dependencies": {
|
||||
"@openai/harmony": "file:../../javascript",
|
||||
"@radix-ui/react-collapsible": "^1.1.11",
|
||||
"@radix-ui/react-label": "^2.1.7",
|
||||
"@radix-ui/react-popover": "^1.1.14",
|
||||
"@radix-ui/react-select": "^2.2.5",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@radix-ui/react-switch": "^1.2.5",
|
||||
"@radix-ui/react-tabs": "^1.1.12",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@tanstack/react-query": "^5.83.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
|
|
|
@ -13,10 +13,23 @@ import {
|
|||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
load_harmony_encoding,
|
||||
type JsHarmonyEncoding,
|
||||
type Message as HarmonyMessage,
|
||||
initSync as initHarmony,
|
||||
JsStreamableParser,
|
||||
} from "@openai/harmony";
|
||||
|
@ -213,18 +226,58 @@ function HighlightedTokens({
|
|||
);
|
||||
}
|
||||
|
||||
type Message = {
|
||||
role: "assistant" | "user" | "system" | "developer" | "tool";
|
||||
channel?: string;
|
||||
recipient?: string;
|
||||
content_type?: string;
|
||||
content: {
|
||||
type: "text";
|
||||
text: string;
|
||||
}[];
|
||||
};
|
||||
type Message = HarmonyMessage;
|
||||
|
||||
function MessageItem({
|
||||
message,
|
||||
onUpdateContent,
|
||||
onUpdateHeader,
|
||||
}: {
|
||||
message: Message;
|
||||
onUpdateContent?: (contentIndex: number, newText: string) => void;
|
||||
onUpdateHeader?: (updates: Partial<Message>) => void;
|
||||
}) {
|
||||
const [isHeaderOpen, setIsHeaderOpen] = useState(false);
|
||||
const [draft, setDraft] = useState<Message>(message);
|
||||
|
||||
useEffect(() => {
|
||||
if (isHeaderOpen) {
|
||||
setDraft(message);
|
||||
}
|
||||
}, [isHeaderOpen, message]);
|
||||
|
||||
const commitHeaderUpdates = () => {
|
||||
const normalize = (val?: string) =>
|
||||
val && val.trim().length > 0 ? val.trim() : undefined;
|
||||
const nextAuthor = {
|
||||
role: draft.author.role,
|
||||
name: normalize(draft.author?.name),
|
||||
} as Message["author"];
|
||||
let nextRecipient = normalize(draft.recipient);
|
||||
if (nextAuthor.role === "tool" && !nextRecipient)
|
||||
nextRecipient = "assistant";
|
||||
onUpdateHeader?.({
|
||||
author: nextAuthor,
|
||||
channel: normalize(draft.channel),
|
||||
recipient: nextRecipient,
|
||||
content_type: normalize(draft.content_type),
|
||||
});
|
||||
};
|
||||
const adjustTextareaSize = (el: HTMLTextAreaElement) => {
|
||||
const style = window.getComputedStyle(el);
|
||||
const lineHeight = parseFloat(style.lineHeight || "16");
|
||||
const paddingTop = parseFloat(style.paddingTop || "0");
|
||||
const paddingBottom = parseFloat(style.paddingBottom || "0");
|
||||
const oneLineHeight = lineHeight + paddingTop + paddingBottom;
|
||||
const maxHeight = lineHeight * 5 + paddingTop + paddingBottom;
|
||||
|
||||
el.style.height = "auto";
|
||||
const desired = Math.max(oneLineHeight, el.scrollHeight);
|
||||
const nextHeight = Math.min(desired, maxHeight);
|
||||
el.style.height = `${nextHeight}px`;
|
||||
el.style.overflowY = desired > maxHeight ? "auto" : "hidden";
|
||||
};
|
||||
|
||||
function MessageItem({ message }: { message: Message }) {
|
||||
return (
|
||||
<div className="text-sm border rounded-md p-1">
|
||||
<div className="border border-dashed border-gray-300 rounded-md">
|
||||
|
@ -241,49 +294,198 @@ function MessageItem({ message }: { message: Message }) {
|
|||
</CollapsibleTrigger>
|
||||
</div>
|
||||
<CollapsibleContent>
|
||||
<div className="p-2 flex flex-col gap-1 mt-1">
|
||||
<dl className="text-xs flex gap-1">
|
||||
<dt>role:</dt>
|
||||
<dd className="font-semibold bg-blue-300/50 px-1 rounded-sm">
|
||||
{message.role}
|
||||
</dd>
|
||||
</dl>
|
||||
{message.channel && (
|
||||
<dl className="text-xs flex gap-1">
|
||||
<dt>content:</dt>
|
||||
<dd className="font-semibold bg-blue-300/50 px-1 rounded-sm">
|
||||
{message.channel}
|
||||
</dd>
|
||||
</dl>
|
||||
)}
|
||||
{message.recipient && (
|
||||
<dl className="text-xs flex gap-1">
|
||||
<dt>recipient:</dt>
|
||||
<dd className="font-semibold bg-blue-300/50 px-1 rounded-sm">
|
||||
{message.recipient}
|
||||
</dd>
|
||||
</dl>
|
||||
)}
|
||||
{message.content_type && (
|
||||
<dl className="text-xs flex gap-1">
|
||||
<dt>content_type:</dt>
|
||||
<dd className="font-semibold bg-blue-300/50 px-1 rounded-sm">
|
||||
{message.content_type}
|
||||
</dd>
|
||||
</dl>
|
||||
)}
|
||||
</div>
|
||||
<Popover
|
||||
open={isHeaderOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (!open && isHeaderOpen) {
|
||||
commitHeaderUpdates();
|
||||
}
|
||||
setIsHeaderOpen(open);
|
||||
}}
|
||||
>
|
||||
<PopoverTrigger asChild>
|
||||
<div className="p-2 flex flex-col gap-1 mt-1 cursor-pointer hover:bg-gray-50 rounded-sm">
|
||||
<dl className="text-xs flex gap-1 items-center">
|
||||
<dt>role:</dt>
|
||||
<dd className="font-semibold bg-blue-300/50 px-1 rounded-sm">
|
||||
{message.author?.role === "tool" && message.author?.name
|
||||
? `${message.author.role} (${message.author.name})`
|
||||
: message.author?.role}
|
||||
</dd>
|
||||
</dl>
|
||||
{message.channel && (
|
||||
<dl className="text-xs flex gap-1 items-center">
|
||||
<dt>channel:</dt>
|
||||
<dd className="font-semibold bg-blue-300/50 px-1 rounded-sm">
|
||||
{message.channel}
|
||||
</dd>
|
||||
</dl>
|
||||
)}
|
||||
{message.recipient && (
|
||||
<dl className="text-xs flex gap-1 items-center">
|
||||
<dt>recipient:</dt>
|
||||
<dd className="font-semibold bg-blue-300/50 px-1 rounded-sm">
|
||||
{message.recipient}
|
||||
</dd>
|
||||
</dl>
|
||||
)}
|
||||
{message.content_type && (
|
||||
<dl className="text-xs flex gap-1 items-center">
|
||||
<dt>content_type:</dt>
|
||||
<dd className="font-semibold bg-blue-300/50 px-1 rounded-sm">
|
||||
{message.content_type}
|
||||
</dd>
|
||||
</dl>
|
||||
)}
|
||||
</div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80">
|
||||
<div className="flex items-center gap-1 mb-3">
|
||||
{(
|
||||
[
|
||||
"user",
|
||||
"assistant",
|
||||
"developer",
|
||||
"system",
|
||||
"tool",
|
||||
] as const
|
||||
).map((r) => (
|
||||
<button
|
||||
key={r}
|
||||
className={cn(
|
||||
"text-xs px-2 py-1 rounded-sm border",
|
||||
draft.author?.role === r
|
||||
? "bg-gray-200 border-gray-300"
|
||||
: "border-transparent hover:bg-gray-50"
|
||||
)}
|
||||
onClick={() =>
|
||||
setDraft((prev) => ({
|
||||
...prev,
|
||||
author: { role: r, name: prev.author?.name } as any,
|
||||
}))
|
||||
}
|
||||
>
|
||||
{r}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{draft.author?.role === "assistant" && (
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs text-gray-500">Channel</label>
|
||||
<Select
|
||||
value={draft.channel}
|
||||
onValueChange={(val) =>
|
||||
setDraft((p) => ({ ...p, channel: val }))
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select channel" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="analysis">analysis</SelectItem>
|
||||
<SelectItem value="commentary">commentary</SelectItem>
|
||||
<SelectItem value="final">final</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs text-gray-500">Recipient</label>
|
||||
<input
|
||||
className="border rounded-md px-2 py-1 text-sm outline-none focus:ring-2 focus:ring-blue-300"
|
||||
value={draft.recipient ?? ""}
|
||||
placeholder="e.g. functions.lookup_weather"
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
setDraft((p) => ({ ...p, recipient: value }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs text-gray-500">
|
||||
Content type
|
||||
</label>
|
||||
<input
|
||||
className="border rounded-md px-2 py-1 text-sm outline-none focus:ring-2 focus:ring-blue-300"
|
||||
value={draft.content_type ?? ""}
|
||||
placeholder="e.g. json"
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
setDraft((p) => ({ ...p, content_type: value }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{draft.author?.role === "tool" && (
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs text-gray-500">Tool name</label>
|
||||
<input
|
||||
className="border rounded-md px-2 py-1 text-sm outline-none focus:ring-2 focus:ring-blue-300"
|
||||
value={draft.author?.name ?? ""}
|
||||
placeholder="e.g. functions.get_weather"
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
setDraft((p) => ({
|
||||
...p,
|
||||
author: { role: p.author.role, name: value } as any,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs text-gray-500">Channel</label>
|
||||
<Select
|
||||
value={draft.channel}
|
||||
onValueChange={(val) =>
|
||||
setDraft((p) => ({ ...p, channel: val }))
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select channel" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="analysis">analysis</SelectItem>
|
||||
<SelectItem value="commentary">commentary</SelectItem>
|
||||
<SelectItem value="final">final</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-xs text-gray-500">Recipient</label>
|
||||
<input
|
||||
className="border rounded-md px-2 py-1 text-sm outline-none focus:ring-2 focus:ring-blue-300"
|
||||
value={draft.recipient ?? ""}
|
||||
placeholder="assistant"
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.value;
|
||||
setDraft((p) => ({ ...p, recipient: value }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
</div>
|
||||
<div className="text-sm flex flex-col gap-4 mt-3 mb-1">
|
||||
{message.content.map((content: any, idx: number) => (
|
||||
<pre
|
||||
className="bg-gray-100/50 p-4 rounded-md text-xs overflow-x-scroll"
|
||||
key={idx}
|
||||
>
|
||||
{content.text}
|
||||
</pre>
|
||||
<textarea
|
||||
key={`${idx}-${content?.text ?? ""}`}
|
||||
className="bg-gray-100/50 p-3 rounded-md text-base w-full resize-y focus:outline-none focus:ring-2 focus:ring-blue-300"
|
||||
rows={1}
|
||||
defaultValue={content.text}
|
||||
ref={(el) => {
|
||||
if (el) adjustTextareaSize(el);
|
||||
}}
|
||||
onInput={(e) => adjustTextareaSize(e.currentTarget)}
|
||||
onBlur={(e) => onUpdateContent?.(idx, e.currentTarget.value)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -328,12 +530,15 @@ function useTokens(text: string | undefined) {
|
|||
const tokens = Array.from(encoding.encode(text, encoding.specialTokens()));
|
||||
// @ts-ignore
|
||||
const tokenTexts = tokens.map((t) => encoding.decodeUtf8([t]));
|
||||
const parser = new JsStreamableParser(encoding, "user");
|
||||
const parser = new JsStreamableParser(encoding);
|
||||
for (const token of tokens) {
|
||||
parser.process(token);
|
||||
}
|
||||
const messages = JSON.parse(parser.messages).map((m: any) => ({
|
||||
...m,
|
||||
const messages: Message[] = JSON.parse(parser.messages).map((m: any) => ({
|
||||
author: { role: m.role, name: m.name },
|
||||
channel: m.channel,
|
||||
recipient: m.recipient,
|
||||
content_type: m.content_type,
|
||||
content:
|
||||
typeof m.content === "string"
|
||||
? [{ type: "text", text: m.content }]
|
||||
|
@ -348,16 +553,84 @@ function useTokens(text: string | undefined) {
|
|||
});
|
||||
}, [text, encoding]);
|
||||
|
||||
const convertTokensToAll = (tokens: number[]) => {
|
||||
if (!encoding) return;
|
||||
// @ts-ignore
|
||||
const tokenTexts = tokens.map((t) => encoding.decodeUtf8([t]));
|
||||
const parser = new JsStreamableParser(encoding);
|
||||
for (const token of tokens) parser.process(token);
|
||||
const messages: Message[] = JSON.parse(parser.messages).map((m: any) => ({
|
||||
author: { role: m.role, name: m.name },
|
||||
channel: m.channel,
|
||||
recipient: m.recipient,
|
||||
content_type: m.content_type,
|
||||
content:
|
||||
typeof m.content === "string"
|
||||
? [{ type: "text", text: m.content }]
|
||||
: m.content,
|
||||
}));
|
||||
setTokenData({ tokens: Array.from(tokens), tokenTexts, messages });
|
||||
};
|
||||
|
||||
const convertTextToAll = (newText: string) => {
|
||||
if (!encoding) return;
|
||||
const tokens = Array.from(
|
||||
encoding.encode(newText, encoding.specialTokens())
|
||||
);
|
||||
convertTokensToAll(tokens);
|
||||
};
|
||||
|
||||
return {
|
||||
...tokenData,
|
||||
highlightedIndex,
|
||||
setHighlightedIndex,
|
||||
setTokens: (newTokens: number[]) => convertTokensToAll(newTokens),
|
||||
setTokenTexts: (newTokenTexts: string | string[]) =>
|
||||
convertTextToAll(
|
||||
Array.isArray(newTokenTexts) ? newTokenTexts.join("") : newTokenTexts
|
||||
),
|
||||
setMessages: (newMessages: Message[]) => {
|
||||
// Flatten author for WASM (serde(flatten) expects top-level role/name)
|
||||
const wasmMessages = newMessages.map((m) => ({
|
||||
role: m.author.role,
|
||||
name: m.author.name,
|
||||
channel: m.channel,
|
||||
recipient: m.recipient,
|
||||
content_type: m.content_type,
|
||||
content: (m.content || []).map((c: any) =>
|
||||
typeof c === "string" ? { type: "text", text: c } : c
|
||||
),
|
||||
}));
|
||||
|
||||
const tokenIds = encoding?.renderConversation(
|
||||
{
|
||||
messages: wasmMessages as any,
|
||||
},
|
||||
{
|
||||
auto_drop_analysis: false,
|
||||
}
|
||||
);
|
||||
if (!tokenIds) return;
|
||||
const tokenIdsArray = Array.from(tokenIds);
|
||||
// @ts-ignore
|
||||
const tokenTexts = tokenIdsArray.map((t) => encoding?.decodeUtf8([t]));
|
||||
|
||||
setTokenData({
|
||||
tokens: tokenIdsArray,
|
||||
tokenTexts: tokenTexts.filter((t) => t !== undefined),
|
||||
messages: newMessages,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [text, setText] = useState(
|
||||
`<|start|>user<|message|>What is the weather in SF?<|end|><|start|>assistant<|channel|>analysis<|message|>User asks: “What is the weather in SF?” We need to use lookup_weather tool.<|end|><|start|>assistant to=functions.lookup_weather<|channel|>commentary <|constrain|>json<|message|>{"location": "San Francisco"}<|end|><|start|>assistant`
|
||||
`<|start|>user<|message|>What is the weather in SF?<|end|>` +
|
||||
`<|start|>assistant<|channel|>analysis<|message|>User asks: “What is the weather in SF?” We need to use lookup_weather tool.<|end|>` +
|
||||
`<|start|>assistant<|channel|>commentary to=functions.lookup_weather<|constrain|>json<|message|>{"location": "San Francisco"}<|end|>` +
|
||||
`<|start|>assistant`
|
||||
// ""
|
||||
);
|
||||
const {
|
||||
tokens,
|
||||
|
@ -365,6 +638,8 @@ function App() {
|
|||
highlightedIndex,
|
||||
setHighlightedIndex,
|
||||
messages,
|
||||
setTokens,
|
||||
setMessages,
|
||||
} = useTokens(text);
|
||||
|
||||
const [wrapWhitespace, setWrapWhitespace] = useState(true);
|
||||
|
@ -416,14 +691,61 @@ function App() {
|
|||
<h3 className="text-sm font-semibold text-gray-700 mb-2">Messages</h3>
|
||||
<div className="flex flex-col gap-4">
|
||||
{messages.map((message: Message, idx: number) => (
|
||||
<MessageItem key={idx} message={message} />
|
||||
<MessageItem
|
||||
key={idx}
|
||||
message={message}
|
||||
onUpdateContent={(contentIndex, newText) => {
|
||||
const updatedMessages = messages.map(
|
||||
(existingMessage: Message, messageIndex: number) => {
|
||||
if (messageIndex !== idx) return existingMessage;
|
||||
const newContent = (existingMessage.content || []).map(
|
||||
(c: any, ci: number) =>
|
||||
ci === contentIndex ? { ...c, text: newText } : c
|
||||
);
|
||||
return { ...existingMessage, content: newContent };
|
||||
}
|
||||
);
|
||||
setMessages(updatedMessages);
|
||||
}}
|
||||
onUpdateHeader={(updates) => {
|
||||
const updatedMessages = messages.map(
|
||||
(existingMessage: Message, messageIndex: number) => {
|
||||
if (messageIndex !== idx) return existingMessage;
|
||||
const next: Message = {
|
||||
...existingMessage,
|
||||
...updates,
|
||||
author: {
|
||||
...(existingMessage.author || { role: "user" }),
|
||||
...(updates as any).author,
|
||||
},
|
||||
} as Message;
|
||||
const normalize = (val?: string) =>
|
||||
val && val.length > 0 ? val : undefined;
|
||||
next.channel = normalize(next.channel);
|
||||
next.recipient = normalize(next.recipient);
|
||||
next.content_type = normalize(next.content_type);
|
||||
return next;
|
||||
}
|
||||
);
|
||||
setMessages(updatedMessages);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{/* <Button
|
||||
<Button
|
||||
variant="outline"
|
||||
className="border border-dashed border-gray-300 rounded-md text-center py-8 text-sm text-gray-500 cursor-pointer"
|
||||
onClick={() =>
|
||||
setMessages([
|
||||
...messages,
|
||||
{
|
||||
author: { role: "user" },
|
||||
content: [{ type: "text", text: "" }],
|
||||
} as Message,
|
||||
])
|
||||
}
|
||||
>
|
||||
<PlusIcon /> Add new message
|
||||
</Button> */}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
|
@ -454,9 +776,13 @@ function App() {
|
|||
onHover={setHighlightedIndex}
|
||||
wrapWhitespace={wrapWhitespace}
|
||||
highlightTokens={highlightTokens}
|
||||
editable={true}
|
||||
onEdit={(text) =>
|
||||
typeof text === "string" && setTokens(JSON.parse(text))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{/* <div className="flex flex-col md:flex-row gap-2">
|
||||
<div className="flex flex-col md:flex-row gap-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch
|
||||
id="wrap-whitespace"
|
||||
|
@ -473,7 +799,7 @@ function App() {
|
|||
/>
|
||||
<Label htmlFor="highlight-tokens">Highlight Tokens</Label>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
48
demo/harmony-demo/src/components/ui/popover.tsx
Normal file
48
demo/harmony-demo/src/components/ui/popover.tsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Popover({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||
return <PopoverPrimitive.Root data-slot="popover" {...props} />
|
||||
}
|
||||
|
||||
function PopoverTrigger({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
||||
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
||||
}
|
||||
|
||||
function PopoverContent({
|
||||
className,
|
||||
align = "center",
|
||||
sideOffset = 4,
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
||||
return (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
data-slot="popover-content"
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function PopoverAnchor({
|
||||
...props
|
||||
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
||||
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
||||
}
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
185
demo/harmony-demo/src/components/ui/select.tsx
Normal file
185
demo/harmony-demo/src/components/ui/select.tsx
Normal file
|
@ -0,0 +1,185 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Select({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||
return <SelectPrimitive.Root data-slot="select" {...props} />
|
||||
}
|
||||
|
||||
function SelectGroup({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
||||
return <SelectPrimitive.Group data-slot="select-group" {...props} />
|
||||
}
|
||||
|
||||
function SelectValue({
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
||||
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
||||
}
|
||||
|
||||
function SelectTrigger({
|
||||
className,
|
||||
size = "default",
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
||||
size?: "sm" | "default"
|
||||
}) {
|
||||
return (
|
||||
<SelectPrimitive.Trigger
|
||||
data-slot="select-trigger"
|
||||
data-size={size}
|
||||
className={cn(
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectContent({
|
||||
className,
|
||||
children,
|
||||
position = "popper",
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||
return (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
data-slot="select-content"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className
|
||||
)}
|
||||
position={position}
|
||||
{...props}
|
||||
>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectLabel({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
||||
return (
|
||||
<SelectPrimitive.Label
|
||||
data-slot="select-label"
|
||||
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectItem({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
||||
return (
|
||||
<SelectPrimitive.Item
|
||||
data-slot="select-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSeparator({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
||||
return (
|
||||
<SelectPrimitive.Separator
|
||||
data-slot="select-separator"
|
||||
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollUpButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
data-slot="select-scroll-up-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronUpIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollDownButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
data-slot="select-scroll-down-button"
|
||||
className={cn(
|
||||
"flex cursor-default items-center justify-center py-1",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ChevronDownIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectScrollDownButton,
|
||||
SelectScrollUpButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
}
|
66
demo/harmony-demo/src/components/ui/tabs.tsx
Normal file
66
demo/harmony-demo/src/components/ui/tabs.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Tabs({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
||||
return (
|
||||
<TabsPrimitive.Root
|
||||
data-slot="tabs"
|
||||
className={cn("flex flex-col gap-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsList({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.List>) {
|
||||
return (
|
||||
<TabsPrimitive.List
|
||||
data-slot="tabs-list"
|
||||
className={cn(
|
||||
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsTrigger({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
||||
return (
|
||||
<TabsPrimitive.Trigger
|
||||
data-slot="tabs-trigger"
|
||||
className={cn(
|
||||
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function TabsContent({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
||||
return (
|
||||
<TabsPrimitive.Content
|
||||
data-slot="tabs-content"
|
||||
className={cn("flex-1 outline-none", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
|
@ -116,7 +116,6 @@ pub async fn load_harmony_encoding(name: HarmonyEncodingName) -> anyhow::Result<
|
|||
FormattingToken::EndMessageDoneSampling,
|
||||
FormattingToken::EndMessageAssistantToTool,
|
||||
]),
|
||||
conversation_has_function_tools: Arc::new(AtomicBool::new(false)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -411,6 +411,28 @@ where
|
|||
.map_err(LoadError::CoreBPECreationFailed)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub fn load_encoding_from_bytes<S, TS>(
|
||||
bytes: &[u8],
|
||||
expected_hash: Option<&str>,
|
||||
special_tokens: S,
|
||||
pattern: &str,
|
||||
) -> Result<CoreBPE, LoadError>
|
||||
where
|
||||
S: IntoIterator<Item = (TS, Rank)>,
|
||||
TS: Into<String>,
|
||||
{
|
||||
let reader = std::io::BufReader::new(bytes);
|
||||
let encoder =
|
||||
load_tiktoken_vocab(reader, expected_hash).map_err(LoadError::InvalidTiktokenVocabFile)?;
|
||||
CoreBPE::new(
|
||||
encoder,
|
||||
special_tokens.into_iter().map(|(k, v)| (k.into(), v)),
|
||||
pattern,
|
||||
)
|
||||
.map_err(LoadError::CoreBPECreationFailed)
|
||||
}
|
||||
|
||||
/// This returns the path to a file containing the data at `url`. If the file is
|
||||
/// cached, it is used. Otherwise, the file is downloaded and cached.
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
|
|
@ -253,10 +253,18 @@ pub struct JsStreamableParser {
|
|||
#[wasm_bindgen]
|
||||
impl JsStreamableParser {
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new(encoding: &JsHarmonyEncoding, role: &str) -> Result<JsStreamableParser, JsValue> {
|
||||
let parsed_role = Role::try_from(role)
|
||||
.map_err(|_| JsValue::from_str(&format!("unknown role: {role}")))?;
|
||||
let inner = StreamableParser::new(encoding.inner.clone(), Some(parsed_role))
|
||||
pub fn new(
|
||||
encoding: &JsHarmonyEncoding,
|
||||
role: Option<String>,
|
||||
) -> Result<JsStreamableParser, JsValue> {
|
||||
let parsed_role = match role {
|
||||
Some(r) => Some(
|
||||
Role::try_from(r.as_str())
|
||||
.map_err(|_| JsValue::from_str(&format!("unknown role: {r}")))?,
|
||||
),
|
||||
None => None,
|
||||
};
|
||||
let inner = StreamableParser::new(encoding.inner.clone(), parsed_role)
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
||||
Ok(Self { inner })
|
||||
}
|
||||
|
@ -344,8 +352,9 @@ pub async fn load_harmony_encoding(
|
|||
let parsed: HarmonyEncodingName = name
|
||||
.parse::<HarmonyEncodingName>()
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
||||
let encoding =
|
||||
inner_load_harmony_encoding(parsed).map_err(|e| JsValue::from_str(&e.to_string()))?;
|
||||
let encoding = inner_load_harmony_encoding(parsed)
|
||||
.await
|
||||
.map_err(|e| JsValue::from_str(&e.to_string()))?;
|
||||
Ok(JsHarmonyEncoding { inner: encoding })
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue